ll-skills 2.0.2 → 3.0.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 +21 -0
- package/README.md +42 -20
- package/agents/ll-executor.md +1 -0
- package/assets/preamble.md +29 -35
- package/bin/install.js +4 -1
- package/hooks/ll-precompact.js +29 -1
- package/hooks/ll-skills-check-update.js +6 -6
- package/hooks/ll-state.js +30 -2
- package/package.json +3 -2
- package/scripts/evals/README.md +57 -0
- package/scripts/evals/cases/auto-dry-run/assert.sh +35 -0
- package/scripts/evals/cases/auto-dry-run/case.json +8 -0
- package/scripts/evals/cases/auto-dry-run/prompt.txt +1 -0
- package/scripts/evals/cases/auto-empty-repo/assert.sh +25 -0
- package/scripts/evals/cases/auto-empty-repo/case.json +8 -0
- package/scripts/evals/cases/auto-empty-repo/fixture/.gitkeep +0 -0
- package/scripts/evals/cases/auto-empty-repo/prompt.txt +1 -0
- package/scripts/evals/cases/decide-final-round/assert.sh +32 -0
- package/scripts/evals/cases/decide-final-round/case.json +8 -0
- package/scripts/evals/cases/decide-final-round/fixture/README.md +3 -0
- package/scripts/evals/cases/decide-final-round/prompt.txt +1 -0
- package/scripts/evals/cases/executor-block/assert.sh +33 -0
- package/scripts/evals/cases/executor-block/case.json +8 -0
- package/scripts/evals/cases/executor-block/prompt.txt +14 -0
- package/scripts/evals/cases/goal-autonomous/assert.sh +35 -0
- package/scripts/evals/cases/goal-autonomous/case.json +8 -0
- package/scripts/evals/cases/goal-autonomous/fixture/PLAN.md +42 -0
- package/scripts/evals/cases/goal-autonomous/fixture/PROGRESS.md +20 -0
- package/scripts/evals/cases/goal-autonomous/fixture/ROADMAP.md +29 -0
- package/scripts/evals/cases/goal-autonomous/fixture/package.json +8 -0
- package/scripts/evals/cases/goal-autonomous/fixture/src/money.js +6 -0
- package/scripts/evals/cases/goal-autonomous/fixture/test/reconcile.test.js +8 -0
- package/scripts/evals/cases/goal-autonomous/prompt.txt +1 -0
- package/scripts/evals/cases/implement-review-gate/assert.sh +35 -0
- package/scripts/evals/cases/implement-review-gate/case.json +8 -0
- package/scripts/evals/cases/implement-review-gate/prompt.txt +1 -0
- package/scripts/evals/cases/implement-stops-at-next/assert.sh +39 -0
- package/scripts/evals/cases/implement-stops-at-next/case.json +9 -0
- package/scripts/evals/cases/implement-stops-at-next/prompt.txt +1 -0
- package/scripts/evals/cases/preamble-no-ritual/assert.sh +17 -0
- package/scripts/evals/cases/preamble-no-ritual/case.json +8 -0
- package/scripts/evals/cases/preamble-no-ritual/fixture/README.md +3 -0
- package/scripts/evals/cases/preamble-no-ritual/fixture/src/a.ts +3 -0
- package/scripts/evals/cases/preamble-no-ritual/prompt.txt +1 -0
- package/scripts/evals/cases/router-execute/assert.sh +12 -0
- package/scripts/evals/cases/router-execute/case.json +8 -0
- package/scripts/evals/cases/router-execute/prompt.txt +1 -0
- package/scripts/evals/cases/router-research/assert.sh +11 -0
- package/scripts/evals/cases/router-research/case.json +8 -0
- package/scripts/evals/cases/router-research/fixture/README.md +3 -0
- package/scripts/evals/cases/router-research/prompt.txt +1 -0
- package/scripts/evals/cases/router-small/assert.sh +21 -0
- package/scripts/evals/cases/router-small/case.json +8 -0
- package/scripts/evals/cases/router-small/fixture/README.md +17 -0
- package/scripts/evals/cases/router-small/prompt.txt +1 -0
- package/scripts/evals/cases/scout-no-plan/assert.sh +41 -0
- package/scripts/evals/cases/scout-no-plan/case.json +8 -0
- package/scripts/evals/cases/scout-no-plan/prompt.txt +8 -0
- package/scripts/evals/cases/verifier-weakened-test/assert.sh +19 -0
- package/scripts/evals/cases/verifier-weakened-test/case.json +8 -0
- package/scripts/evals/cases/verifier-weakened-test/prompt.txt +13 -0
- package/scripts/evals/cases/verifier-weakened-test/setup.sh +19 -0
- package/scripts/evals/fixtures/manual-contract/out.json +29 -0
- package/scripts/evals/fixtures/manual-contract/out.txt +5 -0
- package/scripts/evals/fixtures/manual-contract/with-skill.json +46 -0
- package/scripts/evals/lib/assert.sh +107 -0
- package/scripts/evals/lib/extract.js +73 -0
- package/scripts/evals/run.sh +369 -0
- package/scripts/fixtures/auto-closed/PLAN.md +5 -0
- package/scripts/fixtures/auto-closed/PROGRESS.md +20 -0
- package/scripts/fixtures/auto-closed/ROADMAP.md +6 -0
- package/scripts/fixtures/auto-closed/docs/DELIVERY.md +3 -0
- package/scripts/fixtures/auto-decisions/decisions/DEC-0001-taken-alone.md +13 -0
- package/scripts/fixtures/auto-decisions/decisions/DEC-0002-owner.md +13 -0
- package/scripts/fixtures/auto-noroadmap/PLAN.md +20 -0
- package/scripts/fixtures/auto-noroadmap/PROGRESS.md +11 -0
- package/scripts/fixtures/auto-verify-next/PLAN.md +5 -0
- package/scripts/fixtures/auto-verify-next/PROGRESS.md +18 -0
- package/scripts/fixtures/auto-verify-next/ROADMAP.md +5 -0
- package/scripts/fixtures/auto-verify-next/phases/01/PLAN.md +6 -0
- package/scripts/fixtures/evals-auto/auto-dry-run/pass.txt +18 -0
- package/scripts/fixtures/evals-auto/auto-empty-repo/pass.txt +2 -0
- package/scripts/fixtures/evals-auto/goal-autonomous/pass.txt +29 -0
- package/scripts/fixtures/lint-bad/folded-description/SKILL.md +13 -0
- package/scripts/fixtures/lint-bad/model-invocation-false/SKILL.md +10 -0
- package/scripts/fixtures/next-bad/skills/ll-bad/SKILL.md +30 -0
- package/scripts/fixtures/next-good/skills/ll-good/SKILL.md +26 -0
- package/scripts/fixtures/project/PROGRESS.md +4 -0
- package/scripts/lint-contract.cjs +495 -0
- package/scripts/lint-prompts.sh +396 -0
- package/scripts/ll-tools.js +465 -447
- package/scripts/smoke-test.sh +380 -1
- package/skills/ll-auto/SKILL.md +74 -0
- package/skills/ll-auto/references/run.md +75 -0
- package/skills/ll-auto/references/stages.md +66 -0
- package/skills/ll-auto/scripts/ll-auto.js +345 -0
- package/skills/ll-brainstorm/SKILL.md +5 -4
- package/skills/ll-brainstorm/references/decision-policy.md +3 -0
- package/skills/ll-close/SKILL.md +5 -5
- package/skills/ll-close/references/delivery.md +3 -1
- package/skills/ll-decide/SKILL.md +13 -11
- package/skills/ll-decide/references/decision-policy.md +3 -0
- package/skills/ll-decide/references/interview.md +10 -0
- package/skills/ll-decide/references/plan-skeleton.md +14 -14
- package/skills/ll-decide/references/premise-gate.md +7 -0
- package/skills/ll-goal/SKILL.md +22 -4
- package/skills/ll-goal/references/goal-template.md +57 -0
- package/skills/ll-implement/SKILL.md +4 -2
- package/skills/ll-implement/references/decision-policy.md +3 -0
- package/skills/ll-oncall/SKILL.md +3 -2
- package/skills/ll-refine/SKILL.md +3 -2
- package/skills/ll-research/SKILL.md +3 -2
- package/skills/ll-resume/SKILL.md +4 -3
- package/skills/ll-update/SKILL.md +6 -1
- package/skills/ll-verify/SKILL.md +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
Formato baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/). A skill `ll-update` lê este arquivo para mostrar o que mudou entre a versão instalada e a publicada.
|
|
4
4
|
|
|
5
|
+
## [3.0.0] - 2026-09-10
|
|
6
|
+
|
|
7
|
+
### Adicionado
|
|
8
|
+
|
|
9
|
+
- **`ll-auto`**: skill que roda o ciclo inteiro a partir do estado em disco — research, brainstorm, decide, fases, verificações, close — seguindo o `SKILL.md` de cada etapa em vigor, com as flags `"<objetivo>"`, `--research`, `--brainstorm`, `--interactive`, `--auto-decision`, `--pause-at <stage|N>`, `--from N`, `--to N`, `--only N`, `--verify all`, `--redo <stage>`, `--dry-run` e `--resume`; escreve `docs/AUTO.md` (objetivo, flags, roteiro, status por etapa) e lista no final toda decisão tomada sozinha, marcada `[decided by absence — revisable]`.
|
|
10
|
+
- Helper `skills/ll-auto/scripts/ll-auto.js` (Node puro, sem dependências, próprio da skill): `detect`, `roteiro`, `next-cmd`, `report`, `auto-md`.
|
|
11
|
+
- `--no-talk` em `ll-decide` e `ll-close`: nenhum bloco de pergunta é enviado; itens de faixa 2/3 tomam a recomendação como `ASM-n [decided by absence — revisable]`, itens de faixa 1 viram decisão `WAITING`.
|
|
12
|
+
- **`ll-goal --autonomous`**: modo que aponta o texto do `/goal` para `ll-auto --auto-decision` até a entrega inteira fechar, em vez de uma fase; sem a parte BUDGET, frontmatter com `mode: autonomous` em vez de `ceiling_usd`.
|
|
13
|
+
- Casos de eval `auto-dry-run` e `auto-empty-repo` (`scripts/evals/cases/`), a seção offline `evals-auto` do `scripts/smoke-test.sh` e uma repetição real de ambos via `scripts/evals/run.sh`.
|
|
14
|
+
|
|
15
|
+
### Quebras
|
|
16
|
+
|
|
17
|
+
- As skills não são mais invocadas pelo modelo — todas com `disable-model-invocation: true`.
|
|
18
|
+
- Preâmbulo sem roteador de pedidos.
|
|
19
|
+
- Descrições das skills reescritas em uma linha.
|
|
20
|
+
|
|
21
|
+
### Alterado
|
|
22
|
+
|
|
23
|
+
- Lint rule 1 e 3 do `lint-prompts.sh`.
|
|
24
|
+
- Casos de eval `router-*` e `preamble-no-ritual` passam a exigir o comando nomeado e nenhuma chamada da ferramenta Skill; helper `no_tool_use` em `scripts/evals/lib/assert.sh`.
|
|
25
|
+
|
|
5
26
|
## [2.0.2] - 2026-09-08
|
|
6
27
|
|
|
7
28
|
### Alterado
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# LL Skills
|
|
2
2
|
|
|
3
|
-
Um ciclo de trabalho para [Claude Code](https://claude.com/claude-code):
|
|
3
|
+
Um ciclo de trabalho para [Claude Code](https://claude.com/claude-code): 12 skills, 4 agentes, 3 hooks e dois helpers que compartilham o mesmo estado em arquivos versionados do repositório. Um preâmbulo instalado no seu `~/.claude/CLAUDE.md` carrega o bloco de regras da casa — delegação, decisões, prova — que vale para qualquer skill que você chamar. O produto real é a fase: `ll-implement` roda conversa, plano, revisão adversarial, ondas de execução com TDD, verificação de contexto limpo e epílogo em **uma** invocação, e escreve tudo em disco à medida que acontece, para que uma compactação não perca nada.
|
|
4
4
|
|
|
5
5
|
## Instalação
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ Requer [Node.js](https://nodejs.org) 18+ (o mesmo que o Claude Code já usa).
|
|
|
10
10
|
npx ll-skills@latest
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
Reinicie o Claude Code ao final. As skills são standalone — sem o prefixo `ll-skills:` — e
|
|
13
|
+
Reinicie o Claude Code ao final. As skills são standalone — sem o prefixo `ll-skills:` — e são chamadas pelo nome (`/ll-implement 3`).
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
npx ll-skills@latest --local # instala em ./.claude, só para o projeto atual
|
|
@@ -25,8 +25,9 @@ O que a instalação **escreve** (em `$CLAUDE_CONFIG_DIR` ou `~/.claude`):
|
|
|
25
25
|
|
|
26
26
|
| Caminho | Conteúdo |
|
|
27
27
|
|---|---|
|
|
28
|
-
| `skills/ll-*/` | as
|
|
28
|
+
| `skills/ll-*/` | as 12 skills, com `SKILL.md` e `references/` |
|
|
29
29
|
| `skills/ll-{implement,verify,close}/scripts/ll-tools.js` | cópia do helper, uma por skill que o usa |
|
|
30
|
+
| `skills/ll-auto/scripts/ll-auto.js` | o helper da própria skill, executável |
|
|
30
31
|
| `agents/ll-{executor,scout,verifier,reviewer}.md` | os 4 agentes |
|
|
31
32
|
| `hooks/ll-{skills-check-update,state,precompact}.js` | os 3 hooks, executáveis |
|
|
32
33
|
| `settings.json` | duas entradas em `SessionStart` (`startup\|resume\|compact`) e uma em `PreCompact`; backup em `settings.json.ll-skills.bak` |
|
|
@@ -35,22 +36,9 @@ O que a instalação **escreve** (em `$CLAUDE_CONFIG_DIR` ou `~/.claude`):
|
|
|
35
36
|
|
|
36
37
|
O que a instalação apenas **imprime**, e nunca escreve: a política sugerida de `settings.json` (`assets/settings.suggested.json` — deny list, `autoCompactWindow`, cache, modelos por papel) e o diagnóstico de sobras de instalações antigas. Reinstalar é idempotente; a primeira instalação 2.x poda as skills 1.x pelo manifesto.
|
|
37
38
|
|
|
38
|
-
## Como
|
|
39
|
+
## Como as skills são chamadas
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
| Regime | Gatilho | O que acontece | Skill |
|
|
43
|
-
|---|---|---|---|
|
|
44
|
-
| SMALL | verbo + alvo endereçável, ≤25 palavras, ~3 chamadas | lê o alvo, faz, verifica com um número | nenhuma |
|
|
45
|
-
| FIX | "não era isso", "quebrou", "não sobe" | após 2 tentativas iguais, para, junta evidência, diagnostica | nenhuma |
|
|
46
|
-
| RESEARCH | "pesquise", "compare", "docs oficiais", restrição não validada | frentes paralelas + contra-evidência + checagem de citação | `ll-research` |
|
|
47
|
-
| OPS | deploy, apply, cutover, credencial, IP, "avise a infra" | pré-flight de capacidades e verdade por outro caminho | `ll-oncall` |
|
|
48
|
-
| LARGE | ideia nova, "plano", horas de máquina, cria um lugar | plano de ataque em 5 linhas, depois o contrato | `ll-decide` |
|
|
49
|
-
| EXECUTE | "implementa", "continua", marco com `passes: false` | a fase inteira em uma invocação | `ll-implement` |
|
|
50
|
-
| RESUME | 1º turno num repo com PROGRESS.md, "onde paramos" | briefing de ≤20 linhas, nada escrito | `ll-resume` |
|
|
51
|
-
| REFINE | produto rodando + "melhorar", "fiel ao protótipo" | uma rodada fechada de refino | `ll-refine` |
|
|
52
|
-
|
|
53
|
-
Uma palavra sua vence o classificador (`direto`, `pesquise`, `plano`, `implementa`, `fecha`, `status`). E a regra que amarra o conjunto: **uma skill nunca chama outra**. Cada uma termina num arquivo dentro do repositório e imprime `▶ Next — /clear, depois <comando>`; quem cola é você.
|
|
41
|
+
Uma skill roda só quando você digita `/ll-<nome>`. A sessão nunca inicia uma skill sozinha: quando o pedido parece o trabalho de uma delas, ela responde com o comando exato para você colar e para aí. Uma skill por turno — nenhuma chama outra. Cada uma termina num arquivo dentro do repositório e imprime `▶ Next — /clear, depois <comando>`; quem cola é você. `ll-auto` é a única exceção: o único lugar que segue as instruções de outra skill, e só quando você digita `/ll-auto`.
|
|
54
42
|
|
|
55
43
|
## Ciclo de um projeto
|
|
56
44
|
|
|
@@ -58,7 +46,7 @@ Uma vez por milestone, com a contagem de prompts seus por etapa:
|
|
|
58
46
|
|
|
59
47
|
| Etapa | Prompts | Sai disso |
|
|
60
48
|
|---|---|---|
|
|
61
|
-
| ideia →
|
|
49
|
+
| ideia → `/ll-brainstorm` ou `/ll-research` | 1 | plano de ataque em 5 linhas (LARGE) |
|
|
62
50
|
| `ll-brainstorm` | 0–1 | mapa A/B/C + bateria de ≤4 → `DECISIONS.md` / `OPENING.md` |
|
|
63
51
|
| `ll-research` | 0–1 | `docs/research-<tema>/` com SUMMARY, evidências e fontes |
|
|
64
52
|
| `ll-decide` | 1 + cliques | `PLAN.md`, `ROADMAP.md`, `decisions/`, `PROGRESS.md` vazio |
|
|
@@ -89,7 +77,7 @@ Entre fases, `/clear`: sessão nova custa menos e erra menos que compactação.
|
|
|
89
77
|
| `ll-brainstorm` | "tenho uma ideia", "vamos discutir", antes de abrir uma fase | `phases/NN/DECISIONS.md` ou `docs/decide/OPENING.md` |
|
|
90
78
|
| `ll-research` | "pesquise", "compare A e B", restrição não validada; `--market` para mercado e preço | `docs/research-<tema>/` (SUMMARY + evidências + fontes datadas) |
|
|
91
79
|
| `ll-decide` | "escreve o plano", segunda tentativa, ou feedback externo em docx/pdf/xlsx | `PLAN.md` §0–§11, `ROADMAP.md`, `decisions/`, ou `docs/review-<data>.md` |
|
|
92
|
-
| `ll-goal` | antes de uma noite sem ninguém olhando | `docs/GOAL.md` + o texto de 9 partes para `/goal` |
|
|
80
|
+
| `ll-goal` | antes de uma noite sem ninguém olhando; `ll-goal --autonomous ["<objetivo>"]` cobre a entrega inteira | `docs/GOAL.md` + o texto de 9 partes para `/goal`; no modo autônomo, o texto mantém `ll-auto --auto-decision` rodando até a entrega fechar |
|
|
93
81
|
| `ll-implement` | "implementa a fase N", "continua" | a fase entregue, `phases/NN/PLAN.md`, PROGRESS carimbado |
|
|
94
82
|
| `ll-verify` | "confere se terminou de verdade", contrato público, dinheiro, dado de cliente | `VERIFICATION.md` com ledger FRESH/STALE e dois selos |
|
|
95
83
|
| `ll-close` | "fecha", "pode arquivar"; `--milestone` arquiva as fases | `docs/DELIVERY.md`, retrospectiva, ROADMAP colapsado |
|
|
@@ -97,6 +85,30 @@ Entre fases, `/clear`: sessão nova custa menos e erra menos que compactação.
|
|
|
97
85
|
| `ll-refine` | produto rodando: "melhorar as telas", "fiel ao protótipo" | uma rodada registrada no PROGRESS; modo `visual` até o veredito FIEL |
|
|
98
86
|
| `ll-oncall` | `claude -n <papel>`, "vigie a cada 1h", deploy/apply/cutover | bloco `## Federation`, `docs/REQUESTS.md`, pré-flight do deploy |
|
|
99
87
|
| `ll-update` | "atualiza o ll-skills", ou o aviso da sessão | o pacote atualizado, com o changelog mostrado antes |
|
|
88
|
+
| `ll-auto` | `/ll-auto "<objetivo>" [flags]` | `docs/AUTO.md` e o ciclo inteiro |
|
|
89
|
+
|
|
90
|
+
### Fluxo autônomo
|
|
91
|
+
|
|
92
|
+
`ll-auto` lê o estado em disco (`detect`), corta a lista de etapas com as flags (`roteiro`) e segue cada etapa lendo o `SKILL.md` dela — a única skill que faz isso, e só porque você digitou o comando.
|
|
93
|
+
|
|
94
|
+
| Flag | Efeito |
|
|
95
|
+
|---|---|
|
|
96
|
+
| `--research` | entra `research` no roteiro, se não estiver `done` |
|
|
97
|
+
| `--brainstorm` | entra `brainstorm` no roteiro, se não estiver `done` |
|
|
98
|
+
| `--interactive` | tira o `--no-talk` de `ll-brainstorm`/`ll-implement`: essas etapas falam com você |
|
|
99
|
+
| `--auto-decision` | resolve toda decisão de dono para a opção recomendada e segue |
|
|
100
|
+
| `--pause-at <stage\|N>` | para depois daquela etapa ou fase, com `▶ Next — /clear, then ll-auto --resume` |
|
|
101
|
+
| `--from N` / `--to N` / `--only N` | corta as fases por número (`--only N` corta o `close`) |
|
|
102
|
+
| `--verify all` | roda `ll-verify NN` depois de cada fase, mesmo sem o epílogo pedir |
|
|
103
|
+
| `--redo <stage>` | força uma etapa `done` de volta para `todo` |
|
|
104
|
+
| `--dry-run` | imprime a tabela do roteiro e para, antes de escrever `docs/AUTO.md` |
|
|
105
|
+
| `--resume` | retoma as flags gravadas em `docs/AUTO.md`, a partir da primeira linha que não é `done` |
|
|
106
|
+
|
|
107
|
+
Num repositório vazio (sem pesquisa, sem `OPENING.md`, sem `PLAN.md`) e sem objetivo, `ll-auto` não pergunta nada: imprime o comando que completa (`/ll-auto "<objetivo>" [--research] [--brainstorm]`) e para. Toda decisão de dono tomada sozinha ao longo do run (com `--auto-decision`) entra listada no fim, cada uma marcada `[decided by absence — revisable]`.
|
|
108
|
+
|
|
109
|
+
#### Para rodar sem parar
|
|
110
|
+
|
|
111
|
+
`ll-goal --autonomous` escreve o texto, você cola em `/goal <texto>`, e o loop do `/goal` reinicia `ll-auto --auto-decision` sempre que a sessão parar antes da entrega; decisões tomadas sozinhas ficam listadas no fim (`[decided by absence — revisable]`); só dinheiro, produção ou dados de cliente param a corrida.
|
|
100
112
|
|
|
101
113
|
## Agentes
|
|
102
114
|
|
|
@@ -132,6 +144,16 @@ Nenhum agente despacha subagente (profundidade 1) e nenhum pergunta ao dono: uma
|
|
|
132
144
|
| `epilogue` | monta os dados do fim de fase e diz o próximo comando |
|
|
133
145
|
| `phase-stats` | dias com trabalho, dias ociosos, commits por tipo, razão teste/feature |
|
|
134
146
|
|
|
147
|
+
`skills/ll-auto/scripts/ll-auto.js` é o helper próprio da skill `ll-auto` — Node puro, sem dependências, nunca uma cópia de `ll-tools.js`.
|
|
148
|
+
|
|
149
|
+
| Comando | O que faz |
|
|
150
|
+
|---|---|
|
|
151
|
+
| `detect` | lê o estado em disco e devolve a tabela de etapas (`research` … `close`) com status `todo`/`half`/`done` |
|
|
152
|
+
| `roteiro` | corta a tabela do `detect` pelas flags e devolve a lista ordenada de etapas a rodar |
|
|
153
|
+
| `next-cmd` | lê o comando da última linha `▶ Next` de um arquivo |
|
|
154
|
+
| `report` | lista os `decisions/*.md` marcados `[decided by absence — revisable]` |
|
|
155
|
+
| `auto-md` | monta o corpo de `docs/AUTO.md` (objetivo, flags, roteiro, decisões, log) |
|
|
156
|
+
|
|
135
157
|
## Arquivos de estado no repositório
|
|
136
158
|
|
|
137
159
|
```
|
package/agents/ll-executor.md
CHANGED
|
@@ -22,6 +22,7 @@ You execute one milestone of a phase plan. You do not plan, do not decide and do
|
|
|
22
22
|
2. The project's `CLAUDE.md`.
|
|
23
23
|
3. The `### M<n>` blocks of previous waves in `PROGRESS.md`: what was built before you and what they left in `not_verified:`.
|
|
24
24
|
4. Every file in your milestone's `read_first:`, and the section of `phases/NN/CODE-CONTEXT.md` the brief names.
|
|
25
|
+
5. The brief itself, field by field: MILESTONE, PLAN, CONTEXT, FILES, WAVE (your wave and the milestones running in parallel — their files are not yours), TDD, ACCEPTANCE, MODEL, DEC RESERVED (the only ids you may cite in `questions:`), INPUTS (paths that already exist), DO NOT, RETURN.
|
|
25
26
|
|
|
26
27
|
Nothing else. One Read per file; do not re-read a range already in context. Grep before Read on files over 2,000 lines.
|
|
27
28
|
|
package/assets/preamble.md
CHANGED
|
@@ -1,33 +1,24 @@
|
|
|
1
1
|
<!-- ll-skills:preamble v1 -->
|
|
2
2
|
# ll-skills — how this session works
|
|
3
3
|
|
|
4
|
-
## Route every request before acting
|
|
5
|
-
Classify every request by three criteria — intent gap (does it say what it wants, or only what
|
|
6
|
-
hurts?), irreversibility (leaves the repo, costs money, touches prod?) and footprint (one file, one
|
|
7
|
-
service, one system?) — and state the regime and the reason in one line before doing anything.
|
|
8
|
-
- SMALL: verb + addressable target, ≤25 words, fits in ~3 tool calls → read the target, do what is
|
|
9
|
-
authorized, verify with a number, label provenance; no skill, no file, no subagent.
|
|
10
|
-
- FIX: "não era isso", "quebrou", "não sobe" → after 2 failed attempts of the same kind, stop, write
|
|
11
|
-
what was ruled out, gather evidence, present diagnosis + one question with options; fix AND root cause.
|
|
12
|
-
- RESEARCH: "pesquise", "compare", "docs oficiais", unvalidated restriction → `ll-research`.
|
|
13
|
-
- OPS: deploy, apply, cutover, credential, IP, "avise a infra" → `ll-oncall` (ops mode).
|
|
14
|
-
- LARGE: new idea, "plano", hours of machine time, the request creates a place (folder, repo) →
|
|
15
|
-
5-line plan of attack, then `ll-decide project`, or `ll-research <topic>` first when intent is missing.
|
|
16
|
-
- EXECUTE: `phases/NN/PLAN.md` has a milestone with `passes: false`, or "implementa" / "continua" /
|
|
17
|
-
"roda a fase N" → `ll-implement N`.
|
|
18
|
-
- RESUME: first turn in a repo with PROGRESS.md; "status", "onde estamos", "o que tenho pra decidir" → `ll-resume`.
|
|
19
|
-
- REFINE: product running + "melhorar"; external feedback (docx, pdf, sheet); "fiel ao protótipo" →
|
|
20
|
-
`ll-refine`, or `ll-decide feedback`.
|
|
21
|
-
One word from the owner beats the classifier: direto → SMALL; pesquise → RESEARCH; plano → LARGE;
|
|
22
|
-
goal → `ll-goal N`; implementa / continua → EXECUTE; fecha → `ll-close`; status → RESUME; a skill
|
|
23
|
-
named as a suffix of the request also counts. Never change regime silently: when small turns large (bigger
|
|
24
|
-
root cause, operational pain, chained deliveries, a new place), say so in one line and offer once.
|
|
25
|
-
Never in SMALL: spec, plan, PROGRESS, VERIFICATION, premortem, interview, a subagent for what fits in
|
|
26
|
-
3 calls, questions about implementation, two questions in a row, automatic commits.
|
|
27
|
-
|
|
28
4
|
## Skills
|
|
5
|
+
A skill runs only when the owner types `/ll-<name>`. The session never starts one on its own, never
|
|
6
|
+
runs one "on the owner's behalf", never proposes to run one for them and never calls the Skill tool
|
|
7
|
+
on an ll skill; when a request looks like a skill's job it answers with the exact command to paste
|
|
8
|
+
and stops there. `ll-auto` is the single place that follows another skill's instructions, and only
|
|
9
|
+
while the owner invoked `/ll-auto`.
|
|
10
|
+
Commands to name, never to run: research, a comparison or an unvalidated restriction →
|
|
11
|
+
`/ll-research <topic>`; a new idea → `/ll-brainstorm`; a phase whose PLAN still has an open
|
|
12
|
+
milestone, "implementa", "continua" → `/ll-implement N`; "status", "onde estamos", "o que tenho pra
|
|
13
|
+
decidir" → `/ll-resume`; a decision to record → `/ll-decide`; deploy, credential, incident →
|
|
14
|
+
`/ll-oncall`; external feedback on a running product → `/ll-refine`; closing a phase → `/ll-close`.
|
|
15
|
+
A request that is a verb plus an addressable target and fits in about three tool calls gets the work
|
|
16
|
+
itself, not a ritual: read the target, do what is authorized, verify with a number, label provenance;
|
|
17
|
+
no spec, no plan, no PROGRESS entry, no VERIFICATION, no premortem, no interview, no subagent, no
|
|
18
|
+
automatic commit, no two questions in a row. When a small request turns out to be large (a bigger
|
|
19
|
+
root cause, a chained delivery, a new folder or repo), say so in one line and name the command once.
|
|
29
20
|
A skill never invokes another skill and never decides the owner's next request; `ll-implement` covers one
|
|
30
|
-
phase per invocation. Every skill ends in a repository file and prints "▶ Next —
|
|
21
|
+
phase per invocation. Every skill ends in a repository file and prints "▶ Next — /clear, then <command>" for
|
|
31
22
|
the owner to paste; that line ends the turn, no tool call follows it. State lives at the repo root (`PLAN.md`,
|
|
32
23
|
`PROGRESS.md`, `phases/`, `decisions/`), never in a subfolder, written as it happens. Reply to the owner in
|
|
33
24
|
Portuguese, in their words (marco, onda, gate, contexto limpo, fiel); every file is English. Short answer, long proof.
|
|
@@ -45,19 +36,20 @@ unbiased judge and design; haiku never executes or verifies. The reviewer is nev
|
|
|
45
36
|
executor. The per-role profile lives in PLAN.md §7 and is read every wave.
|
|
46
37
|
|
|
47
38
|
## Decisions
|
|
48
|
-
Band 1 — ask, never decide alone:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
39
|
+
Band 1 — ask, never decide alone: irreversible outside the repo (push that deploys, apply with
|
|
40
|
+
destroy, credential in a new place, writes to prod, customer data); price, packaging or a promise to
|
|
41
|
+
a customer; a scope cut of the phase; the number the owner will look at (denominator, window, what
|
|
42
|
+
counts as an event); a recorded rule contradicted by new evidence.
|
|
52
43
|
Band 2 — decide, record `DEC-`, continue: reversible technical detail; the house pattern; who executes;
|
|
53
|
-
a fact readable from the repo or infra; out of the
|
|
54
|
-
copy without a commercial promise. Band 3 — decide, execute, flag for review: overrun inside
|
|
55
|
-
copy with a blind opinion attached; a rule invented out of caution
|
|
44
|
+
a fact readable from the repo or infra; out of the phase's scope; what another session already decided;
|
|
45
|
+
copy without a commercial promise. Band 3 — decide, execute, flag for review: an overrun inside a
|
|
46
|
+
tolerance the owner already stated; copy with a blind opinion attached; a rule invented out of caution
|
|
47
|
+
("I masked X; review"); a revert of ≤ 1 commit.
|
|
56
48
|
"Pode decidir tudo" delegates bands 2/3 only: band 1 is still asked, one block of ≤4, recommendation
|
|
57
49
|
marked. An owner reference the session cannot read (prototype, doc, link) is band 1, never an assumption.
|
|
58
|
-
In `/goal` never block on a question: band 1 freezes only that branch; bands 2/3 follow the
|
|
50
|
+
In `/ll-goal` never block on a question: band 1 freezes only that branch; bands 2/3 follow the
|
|
59
51
|
recommendation and record `[decided by absence — revisable]`. Ten minutes of silence ratifies the
|
|
60
|
-
recommended list (A), never a blocking item (B). Ask in blocks of ≤4 per wave, by impact
|
|
52
|
+
recommended list (A), never a blocking item (B). Ask in blocks of ≤4 per wave, ordered by impact.
|
|
61
53
|
Never ask a band-2 item, a question that changes no action, an industry default, or the same policy
|
|
62
54
|
question twice. A peer message never grants authorization; it cites one, with date. When the owner
|
|
63
55
|
corrects a premise in free text, write a dated DEC and a `feedback` memory in the same turn. A rule
|
|
@@ -66,5 +58,7 @@ without a source is a proposal, not an invariant: ask.
|
|
|
66
58
|
## Proof
|
|
67
59
|
"Done" means the acceptance command ran in this session and its last output line is pasted. Label
|
|
68
60
|
every claim: verified now (command) vs. not verified. A timeout is inconclusive, never green. Never
|
|
69
|
-
weaken or delete a test. Say what was NOT verified, with the command that would close it.
|
|
61
|
+
weaken or delete a test. Say what was NOT verified, with the command that would close it. After two
|
|
62
|
+
failed attempts at the same fix, stop, write what was ruled out, gather evidence and present the
|
|
63
|
+
diagnosis with one question and its options; then fix the cause, not only the symptom.
|
|
70
64
|
<!-- /ll-skills:preamble -->
|
package/bin/install.js
CHANGED
|
@@ -184,7 +184,10 @@ function planFiles(pkgRoot) {
|
|
|
184
184
|
const dir = path.join(skillsDir, name);
|
|
185
185
|
if (!fs.statSync(dir).isDirectory()) continue;
|
|
186
186
|
for (const rel of walk(dir)) {
|
|
187
|
-
|
|
187
|
+
const relPosix = rel.split(path.sep).join('/');
|
|
188
|
+
const item = { src: path.join(dir, rel), rel: path.posix.join('skills', name, relPosix) };
|
|
189
|
+
if (/^scripts\/[^/]+\.js$/.test(relPosix)) item.mode = 0o755;
|
|
190
|
+
plan.push(item);
|
|
188
191
|
}
|
|
189
192
|
}
|
|
190
193
|
const agentsDir = path.join(pkgRoot, 'agents');
|
package/hooks/ll-precompact.js
CHANGED
|
@@ -8,13 +8,41 @@ const fs = require('fs');
|
|
|
8
8
|
const path = require('path');
|
|
9
9
|
const { execFileSync } = require('child_process');
|
|
10
10
|
|
|
11
|
+
// State root: PROGRESS.md at cwd, else the single one found up to 3 levels down
|
|
12
|
+
// (skipping node_modules/.git/dist/build/vendor and docs/history).
|
|
13
|
+
function stateRoot(cwd) {
|
|
14
|
+
if (fs.existsSync(path.join(cwd, 'PROGRESS.md'))) return cwd;
|
|
15
|
+
const skip = new Set(['node_modules', '.git', 'dist', 'build', 'vendor', 'fixtures', 'fixture', 'test', 'tests']);
|
|
16
|
+
const found = [];
|
|
17
|
+
const walk = (dir, depth) => {
|
|
18
|
+
if (depth > 3 || found.length > 1) return;
|
|
19
|
+
let ents;
|
|
20
|
+
try { ents = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
|
21
|
+
for (const e of ents) {
|
|
22
|
+
if (!e.isDirectory() || skip.has(e.name)) continue;
|
|
23
|
+
const sub = path.join(dir, e.name);
|
|
24
|
+
if (path.relative(cwd, sub) === path.join('docs', 'history')) continue;
|
|
25
|
+
if (fs.existsSync(path.join(sub, 'PROGRESS.md'))) found.push(sub); else walk(sub, depth + 1);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
walk(cwd, 1);
|
|
29
|
+
if (found.length > 1) {
|
|
30
|
+
// several candidates: keep those with an ll-state block, then the most recently written
|
|
31
|
+
const stamp = (d) => { try { return fs.statSync(path.join(d, 'PROGRESS.md')).mtimeMs; } catch { return 0; } };
|
|
32
|
+
const withState = found.filter((d) => { try { return /<!--\s*ll-state\s*-->/.test(fs.readFileSync(path.join(d, 'PROGRESS.md'), 'utf8')); } catch { return false; } });
|
|
33
|
+
const pool = withState.length ? withState : found;
|
|
34
|
+
return pool.sort((a, b) => stamp(b) - stamp(a))[0];
|
|
35
|
+
}
|
|
36
|
+
return found.length === 1 ? found[0] : cwd;
|
|
37
|
+
}
|
|
38
|
+
|
|
11
39
|
function main() {
|
|
12
40
|
let input = {};
|
|
13
41
|
try { input = JSON.parse(fs.readFileSync(0, 'utf8')); } catch { input = {}; }
|
|
14
42
|
const cwd = typeof input.cwd === 'string' && input.cwd ? input.cwd : process.cwd();
|
|
15
43
|
const trigger = typeof input.trigger === 'string' && input.trigger ? input.trigger : 'auto';
|
|
16
44
|
|
|
17
|
-
const file = path.join(cwd, 'PROGRESS.md');
|
|
45
|
+
const file = path.join(stateRoot(cwd), 'PROGRESS.md');
|
|
18
46
|
let body;
|
|
19
47
|
try { body = fs.readFileSync(file, 'utf8'); } catch { return; }
|
|
20
48
|
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
// Hook SessionStart do ll-skills. Instalado em <configDir>/hooks/ pelo bin/install.js.
|
|
5
5
|
//
|
|
6
6
|
// Modo leitor (sem argumentos, foreground, sem rede):
|
|
7
|
-
//
|
|
8
|
-
//
|
|
7
|
+
// reads the cache of the previous run and, when a newer version is recorded for the
|
|
8
|
+
// version installed now, emits a short systemMessage. Then it starts the worker mode
|
|
9
9
|
// em background e sai.
|
|
10
10
|
//
|
|
11
11
|
// Modo worker (--worker, background, com rede):
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
// está no registro e a instalação veio de `npx github:`, cai para `git ls-remote` e
|
|
14
14
|
// compara o SHA. Regrava o cache.
|
|
15
15
|
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
16
|
+
// Golden rule: never delay the session start, nothing on stderr, nothing outside
|
|
17
|
+
// its own cache. Any failure ends silently with exit 0.
|
|
18
18
|
|
|
19
19
|
const fs = require('fs');
|
|
20
20
|
const path = require('path');
|
|
@@ -111,7 +111,7 @@ function worker(installed) {
|
|
|
111
111
|
return;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
//
|
|
114
|
+
// Package not published yet: a remote reference is reliable only when installed from GitHub.
|
|
115
115
|
const info = readJson(path.join(STATE_DIR, 'install.json'));
|
|
116
116
|
if (info && info.source === 'github' && info.sha) {
|
|
117
117
|
const remote = gitRemoteSha();
|
|
@@ -152,6 +152,6 @@ function main() {
|
|
|
152
152
|
try {
|
|
153
153
|
main();
|
|
154
154
|
} catch {
|
|
155
|
-
/*
|
|
155
|
+
/* silence */
|
|
156
156
|
}
|
|
157
157
|
process.exit(0);
|
package/hooks/ll-state.js
CHANGED
|
@@ -64,7 +64,7 @@ function parseStateBlockLite(bl) {
|
|
|
64
64
|
if (!line.trim() || /^\s*#/.test(line)) continue;
|
|
65
65
|
let m = /^phase:\s*(.*)$/.exec(line);
|
|
66
66
|
if (m) { st.phase = String(llScalar(m[1])); inM = false; continue; }
|
|
67
|
-
if (/^milestones:\s
|
|
67
|
+
if (/^milestones:\s*(\{\s*\})?$/.test(line)) { inM = true; continue; }
|
|
68
68
|
m = /^(\s*)(M\d+|G-\d+):\s*\{(.*)\}\s*$/.exec(line);
|
|
69
69
|
if (m && inM) {
|
|
70
70
|
st.milestones[m[2]] = llScalar('{' + m[3] + '}');
|
|
@@ -144,10 +144,38 @@ function build(cwd, source) {
|
|
|
144
144
|
return out.slice(0, MAX_LINES - 2).concat(['', board.text]);
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
// State root: PROGRESS.md at cwd, else the single one found up to 3 levels down
|
|
148
|
+
// (skipping node_modules/.git/dist/build/vendor and docs/history).
|
|
149
|
+
function stateRoot(cwd) {
|
|
150
|
+
if (fs.existsSync(path.join(cwd, 'PROGRESS.md'))) return cwd;
|
|
151
|
+
const skip = new Set(['node_modules', '.git', 'dist', 'build', 'vendor', 'fixtures', 'fixture', 'test', 'tests']);
|
|
152
|
+
const found = [];
|
|
153
|
+
const walk = (dir, depth) => {
|
|
154
|
+
if (depth > 3 || found.length > 1) return;
|
|
155
|
+
let ents;
|
|
156
|
+
try { ents = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
|
157
|
+
for (const e of ents) {
|
|
158
|
+
if (!e.isDirectory() || skip.has(e.name)) continue;
|
|
159
|
+
const sub = path.join(dir, e.name);
|
|
160
|
+
if (path.relative(cwd, sub) === path.join('docs', 'history')) continue;
|
|
161
|
+
if (fs.existsSync(path.join(sub, 'PROGRESS.md'))) found.push(sub); else walk(sub, depth + 1);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
walk(cwd, 1);
|
|
165
|
+
if (found.length > 1) {
|
|
166
|
+
// several candidates: keep those with an ll-state block, then the most recently written
|
|
167
|
+
const stamp = (d) => { try { return fs.statSync(path.join(d, 'PROGRESS.md')).mtimeMs; } catch { return 0; } };
|
|
168
|
+
const withState = found.filter((d) => { try { return /<!--\s*ll-state\s*-->/.test(fs.readFileSync(path.join(d, 'PROGRESS.md'), 'utf8')); } catch { return false; } });
|
|
169
|
+
const pool = withState.length ? withState : found;
|
|
170
|
+
return pool.sort((a, b) => stamp(b) - stamp(a))[0];
|
|
171
|
+
}
|
|
172
|
+
return found.length === 1 ? found[0] : cwd;
|
|
173
|
+
}
|
|
174
|
+
|
|
147
175
|
function main() {
|
|
148
176
|
const input = readStdin();
|
|
149
177
|
const cwd = typeof input.cwd === 'string' && input.cwd ? input.cwd : process.cwd();
|
|
150
|
-
const lines = build(cwd, input.source);
|
|
178
|
+
const lines = build(stateRoot(cwd), input.source);
|
|
151
179
|
if (!lines || !lines.length) return;
|
|
152
180
|
process.stdout.write(JSON.stringify({
|
|
153
181
|
hookSpecificOutput: { hookEventName: 'SessionStart', additionalContext: lines.join('\n').trim() },
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ll-skills",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Evidence-driven development pipeline for Claude Code: router preamble,
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Evidence-driven development pipeline for Claude Code: router preamble, 12 skills (auto, brainstorm, research, decide, goal, implement, verify, close, resume, refine, oncall, update), 4 agents, 3 hooks and a state helper",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ll-skills": "bin/install.js"
|
|
7
7
|
},
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"README.md"
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
|
+
"lint": "bash scripts/lint-prompts.sh && node scripts/lint-contract.cjs",
|
|
19
20
|
"test": "bash scripts/smoke-test.sh"
|
|
20
21
|
},
|
|
21
22
|
"engines": {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Behavioural evals
|
|
2
|
+
|
|
3
|
+
`smoke-test.sh` checks what the files say. These cases check what a session *does* with them: each
|
|
4
|
+
installs the package into a throwaway `CLAUDE_CONFIG_DIR`, runs `claude -p` against a throwaway
|
|
5
|
+
copy of a fixture repository, and scores the answer and the work tree with a shell assert.
|
|
6
|
+
|
|
7
|
+
bash scripts/evals/run.sh --dry-run --all # print the commands, call nothing
|
|
8
|
+
bash scripts/evals/run.sh --case router-small --reps 1 # one case, one rep
|
|
9
|
+
bash scripts/evals/run.sh --all # thirteen cases, three reps
|
|
10
|
+
|
|
11
|
+
`--all` | `--case <id>` (repeatable) | `--reps N` (default 3) | `--model <id>` | `--dry-run`.
|
|
12
|
+
Exit 0 when every selected case passed in at least `min_pass` reps (`case.json`, capped at the
|
|
13
|
+
reps actually run, so `--reps 1` means 1 of 1).
|
|
14
|
+
|
|
15
|
+
## Cost
|
|
16
|
+
|
|
17
|
+
Router cases are 1–6 turns and cost cents. The six agent and skill cases run 30–40 turns: dollars
|
|
18
|
+
per rep, tens of dollars for `--all --reps 3` — a skill that fans out subagents costs about a dollar
|
|
19
|
+
per turn-block, so keep routing caps low. Dry run first, then one cheap case.
|
|
20
|
+
|
|
21
|
+
## Autonomous cases
|
|
22
|
+
|
|
23
|
+
`auto-dry-run`, `auto-empty-repo` and `goal-autonomous` run the unattended path end to end: ≤ 12
|
|
24
|
+
turns and cost cents, like the router cases. The prompt is the slash command exactly as the owner
|
|
25
|
+
types it (`/ll-auto --dry-run`, `/ll-auto`, `/ll-goal --autonomous "Deliver phases 07 and 08"`),
|
|
26
|
+
which `claude -p` expands; there is no agent, no fan-out. `goal-autonomous` scores the pasted `/goal`
|
|
27
|
+
text (`ll-auto --auto-decision`, ≤ 4000 chars) and the committed `docs/GOAL.md` (`mode: autonomous`,
|
|
28
|
+
`phase: all`). Their assert scripts are proven offline, without calling `claude -p`, by `npm test`
|
|
29
|
+
(section `evals-auto` in `scripts/smoke-test.sh`) against the fixed answers under
|
|
30
|
+
`scripts/fixtures/evals-auto/<case>/pass.txt`.
|
|
31
|
+
|
|
32
|
+
`max_turns` is a budget, not a measurement: the `num_turns` the result reports counts the skill's `!`
|
|
33
|
+
preprocessor Bash calls together with the model's own tool calls, and a run has ended `success` with
|
|
34
|
+
`num_turns 7` under `--max-turns 4`. Pin each cap above the highest count real reps show (`case.json`
|
|
35
|
+
`note`), so the cap only ever cuts a run that really went long.
|
|
36
|
+
|
|
37
|
+
## Results — outside the repo
|
|
38
|
+
|
|
39
|
+
Each run writes `$LL_EVAL_RESULTS/<YYYY-MM-DD-HHMM>/` (default `~/.claude/ll-skills-evals`, outside the repo): `RESULTS.md`,
|
|
40
|
+
`summary.json`, the installer log and, per rep, `out.json`, `out.txt`, `assert.log`. Work trees
|
|
41
|
+
live under `mktemp -d` outside the repo — so the session under test never discovers this project's
|
|
42
|
+
own `.claude/` or `CLAUDE.md` — and are kept; `RESULTS.md` prints their path.
|
|
43
|
+
|
|
44
|
+
## Add a case
|
|
45
|
+
|
|
46
|
+
`cases/<id>/`: `case.json` (`max_turns`, `history`, `min_pass`, `agent`, `permission_mode`,
|
|
47
|
+
optional `reuse`), `prompt.txt` (`{{WORK}}` becomes the work tree's absolute path), optional
|
|
48
|
+
`fixture/` (else `scripts/fixtures/project`), optional `setup.sh <workdir>`, and
|
|
49
|
+
`assert.sh <workdir> <out.json> <out.txt>` sourcing `lib/assert.sh`.
|
|
50
|
+
|
|
51
|
+
## Environment
|
|
52
|
+
|
|
53
|
+
`env -u CLAUDECODE`, `--strict-mcp-config`, `--permission-mode bypassPermissions` by default.
|
|
54
|
+
`--max-turns` works but is absent from `claude --help`. `--verbose` is required: without it
|
|
55
|
+
`--output-format json` prints only the `result` object, and the regime line — stated in the *first*
|
|
56
|
+
assistant message, before any tool call — cannot be read. A fresh `CLAUDE_CONFIG_DIR` has no auth:
|
|
57
|
+
`run.sh` symlinks `~/.claude/.credentials.json` into it (a copy goes stale on token refresh).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# --dry-run: the stage table and the roteiro are printed, nothing is written, no skill starts.
|
|
3
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")/../../lib" && pwd)/assert.sh"
|
|
4
|
+
|
|
5
|
+
WORK="$1"; OUT_JSON="$2"; OUT_TXT="$3"
|
|
6
|
+
|
|
7
|
+
# The roteiro of the shared fixture, tolerant to a table or a numbered list:
|
|
8
|
+
# each stage and its command on one line.
|
|
9
|
+
contains "$OUT_TXT" 'phase-07.*ll-implement 0?7' 'the roteiro carries the phase-07 row with ll-implement 07'
|
|
10
|
+
contains "$OUT_TXT" 'phase-08.*ll-implement 0?8' 'the roteiro carries the phase-08 row with ll-implement 08'
|
|
11
|
+
contains "$OUT_TXT" 'close.*ll-close' 'the roteiro carries the close row with ll-close'
|
|
12
|
+
|
|
13
|
+
# CA-04: the stage table from detect is printed too, decide already done.
|
|
14
|
+
contains "$OUT_TXT" 'decide.*done' 'the stage table is printed with decide: done'
|
|
15
|
+
|
|
16
|
+
no_path "$WORK/docs/AUTO.md" 'docs/AUTO.md was not written: the dry run stopped before opening the run'
|
|
17
|
+
|
|
18
|
+
# The capture files are the harness's, not the run's: a real rep keeps them under
|
|
19
|
+
# the results dir, the offline check hands them inside the scratch work tree.
|
|
20
|
+
dirty="$(git -C "$WORK" status --porcelain | while IFS= read -r line; do
|
|
21
|
+
path="${line#???}"
|
|
22
|
+
[ "$WORK/$path" = "$OUT_JSON" ] || [ "$path" = "$OUT_JSON" ] && continue
|
|
23
|
+
[ "$WORK/$path" = "$OUT_TXT" ] || [ "$path" = "$OUT_TXT" ] && continue
|
|
24
|
+
printf '%s\n' "$line"
|
|
25
|
+
done)"
|
|
26
|
+
if [ -z "$dirty" ]; then
|
|
27
|
+
ok 'git status --porcelain is empty: nothing was written'
|
|
28
|
+
else
|
|
29
|
+
fail "the working tree was changed: $(printf '%s' "$dirty" | tr '\n' ' ')"
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
no_tool_use "$OUT_JSON" Skill 'no Skill tool call anywhere in the capture'
|
|
33
|
+
no_tool_use "$OUT_JSON" AskUserQuestion 'no AskUserQuestion tool call anywhere in the capture'
|
|
34
|
+
|
|
35
|
+
finish
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"max_turns": 6,
|
|
3
|
+
"history": false,
|
|
4
|
+
"min_pass": 1,
|
|
5
|
+
"agent": null,
|
|
6
|
+
"permission_mode": "bypassPermissions",
|
|
7
|
+
"note": "Proves the --dry-run stop of ll-auto: the stage table and the roteiro are printed, docs/AUTO.md is not written and no skill is started. bypassPermissions so the helper's Bash runs unattended. Shared fixture: scripts/fixtures/project (phase-07 half, phase-08 planned)."
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/ll-auto --dry-run
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# "/ll-auto" on an empty repository -> the two-line stop, no question, nothing written.
|
|
3
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")/../../lib" && pwd)/assert.sh"
|
|
4
|
+
|
|
5
|
+
WORK="$1"; OUT_JSON="$2"; OUT_TXT="$3"
|
|
6
|
+
|
|
7
|
+
contains "$OUT_TXT" 'Nada encontrado neste reposit' 'the answer carries the empty-repository line'
|
|
8
|
+
contains "$OUT_TXT" '/ll-auto "<objetivo>"' 'the answer carries the command to complete'
|
|
9
|
+
|
|
10
|
+
no_path "$WORK/docs" 'no docs/ was created'
|
|
11
|
+
no_path "$WORK/PLAN.md" 'no PLAN.md was created'
|
|
12
|
+
|
|
13
|
+
# OUT_JSON may sit inside WORK for an offline check; exclude it by name so the
|
|
14
|
+
# capture file itself is not read as a change to the work tree.
|
|
15
|
+
dirty="$(git -C "$WORK" status --porcelain 2>/dev/null | grep -v -- " $(basename "$OUT_JSON")\$")"
|
|
16
|
+
if [ -z "$dirty" ]; then
|
|
17
|
+
ok 'git status --porcelain is empty: nothing was written'
|
|
18
|
+
else
|
|
19
|
+
fail "the working tree was changed: $(printf '%s' "$dirty" | tr '\n' ' ')"
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
no_tool_use "$OUT_JSON" AskUserQuestion 'no AskUserQuestion tool call anywhere in the capture'
|
|
23
|
+
no_tool_use "$OUT_JSON" Skill 'no Skill tool call anywhere in the capture'
|
|
24
|
+
|
|
25
|
+
finish
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"max_turns": 10,
|
|
3
|
+
"history": false,
|
|
4
|
+
"min_pass": 1,
|
|
5
|
+
"agent": null,
|
|
6
|
+
"permission_mode": "bypassPermissions",
|
|
7
|
+
"note": "Own fixture holding only .gitkeep (an empty repository). Proves the empty-repo stop: two exact lines, no question, nothing written. max_turns 10 (B-018): the `num_turns` the result reports counts the skill's `!` preprocessor Bash calls and the model's own tool calls together — real reps of this case reported 3 and 7 while the cap was 4 and the run still ended `success`, so the two numbers are not the same unit. The cap is pinned above the highest count seen, so a rep that really runs long is cut instead of scoring."
|
|
8
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/ll-auto
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# The final round is always sent, with the counter, before anything is frozen.
|
|
3
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")/../../lib" && pwd)/assert.sh"
|
|
4
|
+
|
|
5
|
+
WORK="$1"; OUT_JSON="$2"; OUT_TXT="$3"
|
|
6
|
+
|
|
7
|
+
# a one-shot run has no owner to answer: either the final round (counter) or a blocking gate block (≤ 4 questions) is the correct stop
|
|
8
|
+
if grep -qE 'questions asked' "$OUT_TXT"; then
|
|
9
|
+
contains "$OUT_TXT" 'band-1 open' 'the final round carries "band-1 open"'
|
|
10
|
+
else
|
|
11
|
+
contains "$OUT_TXT" '\[PG-1\]|Pergunta 1/|Question 1/' 'the gate asks its first question instead of assuming'
|
|
12
|
+
n="$(grep -cE '^\*\*\[PG-[0-9]+\]|^\*\*Pergunta [0-9]+/|^\*\*Question [0-9]+/' "$OUT_TXT")"
|
|
13
|
+
if [ "$n" -le 4 ]; then ok "the block carries $n questions (≤ 4)"; else fail "the block carries $n questions (> 4)"; fi
|
|
14
|
+
no_path "$WORK/PLAN.md" 'nothing frozen while the gate is open'
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# The contract is only scored when it was written: with a band-1 item open, nothing freezes.
|
|
18
|
+
if [ -f "$WORK/PLAN.md" ]; then
|
|
19
|
+
contains "$WORK/PLAN.md" '^## ' 'PLAN.md carries ## sections'
|
|
20
|
+
if [ -d "$WORK/decisions" ]; then
|
|
21
|
+
ok 'decisions/ exists beside the frozen PLAN.md'
|
|
22
|
+
else
|
|
23
|
+
fail 'PLAN.md was written but decisions/ does not exist'
|
|
24
|
+
fi
|
|
25
|
+
else
|
|
26
|
+
ok 'no PLAN.md written — nothing was frozen, so the contract is not scored'
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
# The phase plan is never written by this skill.
|
|
30
|
+
no_path "$WORK/phases/01/PLAN.md" 'no phases/NN/PLAN.md was written here'
|
|
31
|
+
|
|
32
|
+
finish
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"max_turns": 40,
|
|
3
|
+
"history": false,
|
|
4
|
+
"min_pass": 2,
|
|
5
|
+
"agent": null,
|
|
6
|
+
"permission_mode": "bypassPermissions",
|
|
7
|
+
"note": "Empty fixture so the LARGE route has nowhere to resume from. The final round is always sent, even when every item was band 2/3, so the counter must appear whether or not PLAN.md was frozen."
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
escreva o plano para um serviço que envia lembretes por e-mail
|