Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
169 commits
Select commit Hold shift + click to select a range
1f08a72
feat: single verification script and CI verdict
argentinaluiz Oct 12, 2026
35d928e
fix: generate the route types before type checking the web
argentinaluiz Oct 12, 2026
cc31119
feat: protect main and guard the harness files
argentinaluiz Oct 12, 2026
483db99
Merge pull request #2 from argentinaluiz/feature/harness-guarda
argentinaluiz Oct 12, 2026
8b7c907
fix: close the gaps the review found in the scan and the guard
argentinaluiz Oct 12, 2026
864fc71
Merge pull request #1 from argentinaluiz/feature/harness-ci
argentinaluiz Oct 12, 2026
cc20619
docs: record that the ruleset is applied on the test repository
argentinaluiz Oct 12, 2026
3352ead
Merge pull request #3 from argentinaluiz/docs/harness-estado
argentinaluiz Oct 12, 2026
780e4fe
feat: run the fast checks when the agent ends its turn
argentinaluiz Oct 12, 2026
cf1111c
Merge pull request #6 from argentinaluiz/feature/harness-hook
argentinaluiz Oct 12, 2026
4fdf60d
fix: block the stop hook when the branch base cannot be found
argentinaluiz Oct 12, 2026
3f86e46
Merge pull request #7 from argentinaluiz/bugfix/harness-hook-base
argentinaluiz Oct 12, 2026
7a0785b
fix: make the stop hook warning valid JSON and point to the real fix
argentinaluiz Oct 12, 2026
00e7e74
Merge pull request #8 from argentinaluiz/bugfix/harness-hook-aviso
argentinaluiz Oct 12, 2026
9d8049f
feat: check the acceptance table of the pull request in CI
argentinaluiz Oct 12, 2026
dc2bc56
fix: reject an acceptance table without header and separator
argentinaluiz Oct 12, 2026
999f29f
Merge pull request #9 from argentinaluiz/feature/harness-aceite
argentinaluiz Oct 12, 2026
4c681cf
feat: add a fresh-context reviewer subagent
argentinaluiz Oct 12, 2026
e153c29
docs: require a committed tree before generating the review diff
argentinaluiz Oct 12, 2026
169c7f1
Merge pull request #12 from argentinaluiz/feature/harness-revisor
argentinaluiz Oct 12, 2026
9d40a64
docs: record waiting for the verdict before an admin bypass
argentinaluiz Oct 12, 2026
5c87509
Merge pull request #13 from argentinaluiz:docs/harness-bypass
argentinaluiz Oct 12, 2026
c43b14a
refactor: remove duplication from the verification scripts
argentinaluiz Oct 13, 2026
4adc486
Merge pull request #14 from argentinaluiz/feature/harness-simplify
argentinaluiz Oct 13, 2026
b7d6e07
feat: block the agent's push until the full verification approved it
argentinaluiz Oct 13, 2026
e685555
fix: match the push only where a command can start
argentinaluiz Oct 13, 2026
55fe6e4
fix: close two ways around the push hook
argentinaluiz Oct 13, 2026
b2ded73
Merge pull request #15 from argentinaluiz/feature/harness-push
argentinaluiz Oct 13, 2026
05798f1
docs: reorganize the Docker section of AGENTS.md for agents
argentinaluiz Oct 14, 2026
f3739a6
feat: group the verification by app and let the agent run one app
argentinaluiz Oct 14, 2026
ceb86bc
docs: make the verification script the definition of done
argentinaluiz Oct 14, 2026
89f644c
docs: slim the projects' AGENTS.md down to project decisions
argentinaluiz Oct 14, 2026
efedb3d
chore: add the NestJS, Next.js and React best-practice skills
argentinaluiz Oct 14, 2026
9722614
docs: move the API's Nest conventions into path-scoped rules
argentinaluiz Oct 14, 2026
5d907ab
chore: add the Prisma CLI and Prisma Client skills
argentinaluiz Oct 14, 2026
bae2ab9
feat: load the Prisma CLI config with env() and dotenv (LUI-153)
argentinaluiz Oct 14, 2026
9e02503
docs: say when a read throws and when it returns null (LUI-154)
argentinaluiz Oct 14, 2026
7d14f6a
feat: let a service open a transaction and pass it to repositories (L…
argentinaluiz Oct 14, 2026
36fbb25
feat: add UserPromptSubmit hook to identify and activate relevant skills
argentinaluiz Oct 14, 2026
1976ddf
docs: describe the web and the API components in the LLD
argentinaluiz Oct 14, 2026
68bf8af
docs: plan the ticket plan and machine-checked contract in the harness
argentinaluiz Oct 14, 2026
68f1a47
feat: add the ticket plan flow and the /plan-ticket skill (LUI-157)
argentinaluiz Oct 14, 2026
2742d9b
docs: point the implement skill to the ticket plan rules (LUI-157)
argentinaluiz Oct 14, 2026
2ead113
feat: check the acceptance criteria by ID instead of the PR table (LU…
argentinaluiz Oct 14, 2026
59d37bc
docs: make the reviewer check the ticket criteria against the accepta…
argentinaluiz Oct 14, 2026
0bf373b
feat: freeze the approved acceptance file with a hook and a guard war…
argentinaluiz Oct 14, 2026
02711fd
feat: own the API contract and the schema with machine-checked artifa…
argentinaluiz Oct 14, 2026
81be409
fix: check the acceptance coverage without a PR body and close the ap…
argentinaluiz Oct 14, 2026
b4b538e
fix: remove disable-model-invocation flag from implement-spec documen…
argentinaluiz Oct 14, 2026
fba284a
docs: record the upload and download decisions for feature 02
argentinaluiz Oct 14, 2026
cd2c6c4
docs: plan the Drive and upload screens in Figma (LUI-163)
argentinaluiz Oct 14, 2026
997be9d
docs: describe the upload waiting state, load more and dropped-folder…
argentinaluiz Oct 14, 2026
1d95271
docs: list the measures that stay outside the token scales (LUI-163)
argentinaluiz Oct 14, 2026
826fb47
docs: plan the root folder list (LUI-166)
argentinaluiz Oct 14, 2026
df3a814
feat(api): list the root folder children (LUI-166)
argentinaluiz Oct 14, 2026
86e35cf
feat(web): Drive shell with the account menu (LUI-166)
argentinaluiz Oct 14, 2026
5c9a290
feat(web): list the root folder with load more (LUI-166)
argentinaluiz Oct 14, 2026
40d7c14
test(web): wait for the root folder before seeding items (LUI-166)
argentinaluiz Oct 14, 2026
a54f6ab
fix(api): reject an empty cursor instead of returning the first page …
argentinaluiz Oct 14, 2026
0c4b0e8
docs: let a protected read check the session through its own API call…
argentinaluiz Oct 14, 2026
31e99e2
docs: fix the ticket plan flow with what the pilot showed (LUI-156)
argentinaluiz Oct 14, 2026
7189583
refactor: simplify the root list code after review (LUI-166)
argentinaluiz Oct 14, 2026
b312fa5
docs: plan the web unit suite and the integration check (LUI-164)
argentinaluiz Oct 14, 2026
8d6c25b
feat(harness): add the web unit suite and the integration check mark …
argentinaluiz Oct 14, 2026
13a576e
docs: plan the local storage preparation (LUI-165)
argentinaluiz Oct 14, 2026
bfcf346
feat: add the local storage emulator and the storage interface (LUI-165)
argentinaluiz Oct 14, 2026
1a4204f
docs: plan sending a file (LUI-167)
argentinaluiz Oct 14, 2026
85777f4
feat: send a file with a quota reservation and the upload panel (LUI-…
argentinaluiz Oct 14, 2026
15186ff
fix: refuse blank and dot-only file names and rename the icon-only pr…
argentinaluiz Oct 14, 2026
9179353
docs: plan the readable contract view and the plan drift warning (LUI…
argentinaluiz Oct 14, 2026
af6b99f
feat(harness): show the planned contract readably and warn on plan dr…
argentinaluiz Oct 15, 2026
30ecc72
docs: plan the ticket plan review page (LUI-173)
argentinaluiz Oct 15, 2026
3351b4b
feat(harness): review the ticket plan in a generated page (LUI-173)
argentinaluiz Oct 15, 2026
420160f
docs: plan keeping the plan page after the plan commit (LUI-174)
argentinaluiz Oct 15, 2026
0e2f77c
feat(harness): keep the plan page after the plan commit (LUI-174)
argentinaluiz Oct 15, 2026
7d83027
docs: plan downloading a file (LUI-168)
argentinaluiz Oct 15, 2026
62a614c
feat: download a file through a short-lived signed URL (LUI-168)
argentinaluiz Oct 15, 2026
8226536
docs: plan the portable plan-ticket skill (LUI-175)
argentinaluiz Oct 15, 2026
9667914
feat(harness): make the plan-ticket skill portable and owner of the p…
argentinaluiz Oct 15, 2026
fe385e8
docs: plan running the harness Node over the mounted repository (LUI-…
argentinaluiz Oct 15, 2026
d133489
feat(harness): run the harness Node over the read-only mounted reposi…
argentinaluiz Oct 15, 2026
f456438
docs: plan the pending uploads cleanup command (LUI-169)
argentinaluiz Oct 15, 2026
53d21e3
feat: clean up pending uploads by command (LUI-169)
argentinaluiz Oct 15, 2026
fe14929
docs: plan sending many and large files in chunks (LUI-170)
argentinaluiz Oct 15, 2026
e57fa8f
chore(harness): move each acceptance file into its ticket folder
argentinaluiz Oct 15, 2026
0604c67
feat(harness): run full once per task, keep acceptance in the ticket …
argentinaluiz Oct 15, 2026
47aecc9
feat(harness): deny full to subagents in the Bash hook
argentinaluiz Oct 15, 2026
7431427
feat: send many and large files in chunks (LUI-170)
argentinaluiz Oct 15, 2026
44efdae
fix: purge pending uploads through a deleting claim, as the plan orde…
argentinaluiz Oct 15, 2026
7b3d750
feat(harness): focus the reviewer on conformance and share the checks…
argentinaluiz Oct 15, 2026
809f646
docs: plan resuming an upload after the tab closes (LUI-171)
argentinaluiz Oct 15, 2026
9b49ae9
feat: resume an upload after the tab closes (LUI-171)
argentinaluiz Oct 15, 2026
a6d2bc6
fix: read the login return path before the form renders
argentinaluiz Oct 15, 2026
f531f3b
chore: ignore the Playwright MCP working folder
argentinaluiz Oct 15, 2026
a06477a
chore(harness): move each ticket folder under its parent issue
argentinaluiz Oct 15, 2026
4a0ed2e
feat(harness): keep each ticket folder under its parent issue
argentinaluiz Oct 15, 2026
3395dbe
Merge pull request #16 from argentinaluiz/bugfix/destino-do-login
argentinaluiz Oct 15, 2026
5a2bac6
Merge pull request #17 from argentinaluiz/feature/tickets-por-issue
argentinaluiz Oct 15, 2026
c720ba2
feat(harness): verify at the end of a turn only what the session itse…
argentinaluiz Oct 15, 2026
48ffb91
feat(harness): keep the harness state in an ignored .harness folder
argentinaluiz Oct 15, 2026
7d857fb
refactor(harness): protect the state folder from the edit tools with …
argentinaluiz Oct 15, 2026
c5f8ef7
fix(harness): read paths with parentheses and fail closed on pathless…
argentinaluiz Oct 15, 2026
885d051
fix(web): resync the list after a refresh, close the drawer on deskto…
argentinaluiz Oct 15, 2026
46432f4
Merge remote-tracking branch 'test/bugfix/destino-do-login' into bugf…
argentinaluiz Oct 15, 2026
dcf69bc
Merge branch 'bugfix/destino-do-login' into feature/stop-verify-por-s…
argentinaluiz Oct 15, 2026
83a66ce
Merge pull request #19 from argentinaluiz/bugfix/destino-do-login
argentinaluiz Oct 15, 2026
3424b27
Merge pull request #18 from argentinaluiz/feature/stop-verify-por-sessao
argentinaluiz Oct 15, 2026
5dfa56f
Merge pull request #20 from argentinaluiz/bugfix/destino-do-login
argentinaluiz Oct 15, 2026
7fe56b9
docs: plan shell harness tests entering the acceptance coverage (LUI-…
argentinaluiz Oct 19, 2026
f53dcdb
feat: shell harness tests enter the acceptance coverage (LUI-183)
argentinaluiz Oct 19, 2026
e70e2fc
Merge pull request #17 from devfullcycle/feature/lui-183-testes-shell…
argentinaluiz Oct 19, 2026
c1d266a
docs: plan the development environment following a slot (LUI-184)
argentinaluiz Oct 19, 2026
6a60e41
feat: development environment follows a slot (LUI-184)
argentinaluiz Oct 19, 2026
9f8a423
chore: bring the main of origin into this repository
argentinaluiz Oct 19, 2026
3b6b400
Merge pull request #21 from argentinaluiz/sincronizar-com-origin
argentinaluiz Oct 19, 2026
03360cc
Merge pull request #22 from argentinaluiz/feature/lui-184-ambiente-po…
argentinaluiz Oct 19, 2026
9b20290
docs: plan one full verification at a time and the migration order st…
argentinaluiz Oct 19, 2026
814bdf0
feat: one full verification at a time and the migration order step (L…
argentinaluiz Oct 19, 2026
63c24d1
fix: let the machine write the reports folder the container creates (…
argentinaluiz Oct 19, 2026
251da7b
Merge pull request #23 from argentinaluiz/feature/lui-185-verificacao…
argentinaluiz Oct 19, 2026
0066757
docs: plan the script that creates, lists and removes fronts (LUI-186)
argentinaluiz Oct 19, 2026
6009d41
feat: script that creates, lists and removes parallel fronts (LUI-186)
argentinaluiz Oct 19, 2026
02fe23b
docs: plan the decomposition for parallel fronts (LUI-189)
argentinaluiz Oct 19, 2026
8b31223
docs: decomposition looks for shared decisions between parallel ticke…
argentinaluiz Oct 19, 2026
cfa9941
Merge pull request #24 from argentinaluiz/feature/lui-186-script-de-f…
argentinaluiz Oct 19, 2026
332c4f4
docs: plan the conflicts between fronts in the list (LUI-187)
argentinaluiz Oct 19, 2026
e5c2015
Merge pull request #25 from argentinaluiz/feature/lui-189-decomposica…
argentinaluiz Oct 19, 2026
e445738
feat: the front list shows the conflicts between fronts and with main…
argentinaluiz Oct 19, 2026
8c27bea
docs: plan the skill that brings main into the branch of a front (LUI…
argentinaluiz Oct 19, 2026
11f337f
feat: the sync skill brings main into the branch of a front (LUI-188)
argentinaluiz Oct 19, 2026
940577a
Merge pull request #26 from argentinaluiz/feature/lui-187-conflitos-n…
argentinaluiz Oct 19, 2026
d320644
docs: plan the implement skill as the skill of one ticket (LUI-190)
argentinaluiz Oct 19, 2026
d9c3b05
docs: implement is the skill of one ticket, and implement-spec leaves…
argentinaluiz Oct 19, 2026
d62f4d5
docs: plan the protection of main and the Done by merge (LUI-191)
argentinaluiz Oct 19, 2026
2510ebc
docs: what the merge asks for and the Done that comes from the merge …
argentinaluiz Oct 19, 2026
886cb95
Merge pull request #27 from argentinaluiz/feature/lui-188-sincronizar
argentinaluiz Oct 19, 2026
2e8dd00
Merge pull request #28 from argentinaluiz/feature/lui-190-implement-u…
argentinaluiz Oct 19, 2026
43f874a
Merge pull request #29 from argentinaluiz/feature/lui-191-protecao-da…
argentinaluiz Oct 19, 2026
cdc9342
docs: separate the slots in the browser by profile or host, not by in…
argentinaluiz Oct 19, 2026
54abbc9
docs: one browser profile per slot, without the host trick (LUI-186)
argentinaluiz Oct 19, 2026
1437c7d
Merge pull request #30 from argentinaluiz/docs/lui-186-cookies-entre-…
argentinaluiz Oct 19, 2026
8674f77
docs: close the gaps of the sync skill and make implement and sync co…
argentinaluiz Oct 19, 2026
18f1a51
docs: compare the migrations with the base, and pass the PR body in i…
argentinaluiz Oct 19, 2026
89453ff
Merge pull request #31 from argentinaluiz/bugfix/lui-188-lacunas-da-s…
argentinaluiz Oct 19, 2026
5db8f99
fix: the defects of the fronts script found by the code review of LUI…
argentinaluiz Oct 19, 2026
d1132f2
Merge pull request #32 from argentinaluiz/bugfix/lui-186-defeitos-do-…
argentinaluiz Oct 19, 2026
5b3ae9d
docs: what the Linear and GitHub integration does with the issue of a…
argentinaluiz Oct 19, 2026
3c35005
docs: In Review comes when the pull request opens (LUI-191)
argentinaluiz Oct 19, 2026
8e88ef8
Merge pull request #35 from argentinaluiz/docs/lui-191-in-review-pela…
argentinaluiz Oct 19, 2026
eee0c3c
docs: the rule of the merge as practised, and the CA10 of LUI-186 wit…
argentinaluiz Oct 19, 2026
e520ed6
docs: plan the single base and the honest classification of the conve…
argentinaluiz Oct 19, 2026
4fc07c3
feat: a single base for the harness and an honest classification of t…
argentinaluiz Oct 19, 2026
8bfa9a8
Merge pull request #36 from argentinaluiz/docs/lui-186-regra-do-merge…
argentinaluiz Oct 19, 2026
59571fa
Merge test/main into feature/lui-192 (brings the pull request 36)
argentinaluiz Oct 19, 2026
b38000c
Merge pull request #37 from argentinaluiz/feature/lui-192
argentinaluiz Oct 20, 2026
dbcbd62
feat: skill to open the fronts of the ready tickets of a spec
argentinaluiz Oct 20, 2026
8676ac0
fix: the open-fronts skill finds the work that a worktree check misses
argentinaluiz Oct 20, 2026
1da1dbe
fix: the open-fronts skill tells a stale status from open work
argentinaluiz Oct 20, 2026
d6ec5e1
fix: explain the signs of git cherry in the open-fronts skill
argentinaluiz Oct 20, 2026
b0542ba
Merge pull request #38 from argentinaluiz/feature/skill-abrir-frentes
argentinaluiz Oct 20, 2026
f5cd8ff
fix(harness): restore the deny rules of the settings that a LUI-185 c…
argentinaluiz Oct 20, 2026
79cf44b
docs: align the AGENTS.md with the ticket skills after the evaluation…
argentinaluiz Oct 20, 2026
3a7cee6
Merge pull request #39 from argentinaluiz/feature/restaurar-deny-perm…
argentinaluiz Oct 20, 2026
208ec8b
Merge pull request #40 from argentinaluiz/docs/alinhar-skills-e-agents
argentinaluiz Oct 20, 2026
64086c0
docs: plan the guard and the protected state as a generic skill (LUI-…
argentinaluiz Oct 20, 2026
322d1d6
feat(harness): the guard and the protected state become the generic s…
argentinaluiz Oct 20, 2026
726d2be
refactor(harness): simplify the guard and the state hook of proteger-…
argentinaluiz Oct 20, 2026
5078703
fix(harness): make the guard fail closed on a non-numeric count and o…
argentinaluiz Oct 20, 2026
7486901
fix(harness): apply the conformance review of LUI-194 and cover the u…
argentinaluiz Oct 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 29 additions & 14 deletions .claude/hooks/push-verify.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#!/usr/bin/env bash
#
# Hook de antes do comando do Claude Code (evento PreToolUse, ferramenta Bash). Nega ao agente cinco
# comandos: o `scripts/verify.sh full` a um subagente, porque o modo completo é de quem fecha a tarefa;
# comandos: o `scripts/frentes.sh` com `--forcar`, que abandona uma frente sem merge e é só do usuário, ou
# com as variáveis do modo de teste, que trocam o `gh` e contornariam a conferência do merge;
# o `scripts/verify.sh full` a um subagente, porque o modo completo é de quem fecha a tarefa;
# o `scripts/verify.sh unlock`, que tira a trava do modo completo e é só do usuário; o
# `scripts/verify.sh` com `CI=` ou `GITHUB_ACTIONS=` no comando, que desligaria a trava; o que mexe
# na pasta de estado do harness (`.harness/`), onde ficam a trava e a aprovação; e o `git push`
# `scripts/verify.sh` com `CI=` ou `GITHUB_ACTIONS=` no comando, que desligaria a trava; e o `git push`
# que o `scripts/verify.sh prepush` não aprova, porque os commits trazem segredo ou o modo completo
# não aprovou o último commit. As guardas são para um agente que coopera, e não uma barreira de
# segurança.
Expand All @@ -17,9 +18,9 @@ cd "${CLAUDE_PROJECT_DIR:-$(dirname "$0")/../..}" || exit 0
# A instrução de destravar, a mesma das mensagens do verify.sh (FULL_LOCK_ASK).
# shellcheck source=../../scripts/full-lock.sh
source scripts/full-lock.sh 2>/dev/null
# A leitura do que é mexer na pasta de estado do harness e a das aspas, definidas num lugar só.
# shellcheck source=../../scripts/harness-state-guard.sh
source scripts/harness-state-guard.sh
# A leitura das aspas de um comando de shell, que é da skill proteger-harness.
# shellcheck source=../skills/proteger-harness/scripts/harness-state-guard.sh
source .claude/skills/proteger-harness/scripts/harness-state-guard.sh

# Nega o comando com as linhas dadas.
deny() {
Expand All @@ -31,6 +32,16 @@ deny_unlock() {
deny "O comando foi negado: só o usuário destrava o modo completo." "Como resolver: ${FULL_LOCK_ASK:-}"
}

deny_forcar() {
deny "O comando foi negado: só o usuário abandona uma frente com o \`--forcar\`." \
"O \`frentes.sh remover --forcar\` remove a frente sem o merge e apaga o trabalho dela; abandonar um ticket é decisão do usuário, que a toma no prompt com \`! scripts/frentes.sh remover <ticket> --forcar\`."
}

deny_frentes_test() {
deny "O comando foi negado: o \`frentes.sh\` não roda com as variáveis do modo de teste do harness." \
"\`HARNESS_TEST\`, \`FRENTES_GH\`, \`FRENTES_DOCKER\`, \`FRENTES_PORT_OWNER\` e \`FRENTES_GIT_VERSION\` trocam o \`gh\`, o \`docker\` e as conferências do script, e com elas o \`remover\` removeria uma frente sem o merge. São dos testes do script, que o scripts/verify.sh roda. Rode o \`frentes.sh\` sem elas."
}

deny_ci() {
deny "O comando foi negado: \`CI=\` e \`GITHUB_ACTIONS=\` não vão no comando do scripts/verify.sh." \
"Na máquina, o modo completo conta as reprovações repetidas e trava; essas variáveis desligariam a trava, e o veredito da CI é só da CI. Rode o \`scripts/verify.sh\` sem elas."
Expand All @@ -41,11 +52,6 @@ deny_subagent_full() {
"Termine com os testes ligados aos arquivos que mudou, com os comandos do AGENTS.md do projeto, e devolva o resultado dizendo o que rodou (AGENTS.md da raiz, \"Definição de pronto\")."
}

deny_state() {
deny "O comando foi negado: a pasta de estado do harness (\`.harness/\`) guarda a trava (\`full-lock\`) e a aprovação (\`full-ok\`) do modo completo, e o estado é da verificação, não do agente." \
"Não leia, não apague e não grave nada nela: quem mexe nesse estado é o scripts/verify.sh. Se o modo completo travou: ${FULL_LOCK_ASK:-}"
}

# Uma atribuição de variável de ambiente na frente de um comando.
assignment='[[:alnum:]_]+=[^[:space:]]*[[:space:]]+'
# A posição de um comando: o começo de uma linha ou depois de `;`, `&`, `|` ou `(`, com variáveis de
Expand All @@ -56,6 +62,12 @@ at_command=$'(^|[;&|(\n])[[:space:]]*('"$assignment"')*'
# pegar também o que vem embrulhado (`timeout`, `nohup`, `bash -c`, `eval`, um `if`). Uma mensagem
# que cite os dois também é negada: o hook falha fechado.
verify_unlock='verify\.sh.*unlock'
# O `frentes.sh` com o `--forcar` em qualquer ponto do comando, como o `unlock`: o `remover --forcar`
# abandona uma frente sem merge, e isso é do usuário. Uma mensagem que cite os dois também é negada.
frentes_forcar='frentes\.sh.*--forcar'
# O `frentes.sh` com uma variável do modo de teste, em qualquer ponto do comando: elas trocam o `gh`, e o
# `remover` passaria a ver um PR mergeado que não existe. Só os testes do script as usam.
frentes_test_mode='(HARNESS_TEST|FRENTES_(GH|DOCKER|PORT_OWNER|GIT_VERSION))'
# O modo completo do `verify.sh`, com ou sem apps, em qualquer ponto do comando, como o `unlock`.
verify_full="verify\\.sh[\"']?[[:space:]]+[\"']?full([^[:alnum:]_-]|\$)"
# Uma atribuição da variável CI ou GITHUB_ACTIONS: no começo, depois de um espaço (o que cobre o
Expand All @@ -64,7 +76,8 @@ ci_assignment='(^|[[:space:];&|(])(CI|GITHUB_ACTIONS)='
# A mesma atribuição em qualquer ponto, para a entrada que o hook não consegue ler.
ci_mention='(^|[^[:alnum:]_])(CI|GITHUB_ACTIONS)='

# O `split_quotes` é do scripts/harness-state-guard.sh.
# O `split_quotes` é da skill proteger-harness (scripts/harness-state-guard.sh). A pasta de estado do
# harness (`.harness/`) é negada pelo hook dela (hooks/state-guard.sh), configurado à parte no settings.json.

# Se o comando roda o `verify.sh` com `CI=` ou `GITHUB_ACTIONS=`: a atribuição fora das aspas, com o
# `verify.sh` em qualquer ponto, ou um trecho entre aspas que traga os dois, como o de um `bash -c`.
Expand Down Expand Up @@ -93,14 +106,16 @@ input="$(cat)"
# a falha do `jq` não liberá-lo.
if ! command="$(jq -r '.tool_input.command // empty' <<<"$input" 2>/dev/null)"; then
[[ "$input" =~ $verify_unlock ]] && deny_unlock
harness_state_in_raw "$input" && deny_state
[[ "$input" =~ $frentes_forcar ]] && deny_forcar
[[ "$input" == *frentes.sh* && "$input" =~ $frentes_test_mode ]] && deny_frentes_test
[[ "$input" == *verify.sh* && "$input" =~ $ci_mention ]] && deny_ci
[[ "$input" =~ git.*push ]] || exit 0
command="git push"
fi

[[ "$command" =~ $verify_unlock ]] && deny_unlock
harness_state_touched "$command" && deny_state
[[ "$command" =~ $frentes_forcar ]] && deny_forcar
[[ "$command" == *frentes.sh* && "$command" =~ $frentes_test_mode ]] && deny_frentes_test
# O Claude Code põe o `agent_id` na entrada quando o comando vem de um subagente.
[[ -n "$(jq -r '.agent_id // empty' <<<"$input" 2>/dev/null)" && "$command" =~ $verify_full ]] &&
deny_subagent_full
Expand Down
4 changes: 2 additions & 2 deletions .claude/hooks/record-touched.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
set -uo pipefail
# Sem a pasta de estado do harness (a raiz do projeto não se alcança), não há onde anotar: sai com 0, e
# o hook de fim de turno, que não acha a pasta também, avisa que nada foi verificado.
# shellcheck source=../../scripts/harness-dir.sh
source "${0%/*}/../../scripts/harness-dir.sh"
# shellcheck source=../skills/proteger-harness/scripts/harness-dir.sh
source "${0%/*}/../skills/proteger-harness/scripts/harness-dir.sh"
[[ -n "$HARNESS_DIR" ]] || exit 0
root="${HARNESS_DIR%/.harness}"
cd "$root" 2>/dev/null || exit 0
Expand Down
4 changes: 2 additions & 2 deletions .claude/hooks/stop-verify.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ state_unavailable() {
exit 0
}

# shellcheck source=../../scripts/harness-dir.sh
source "${0%/*}/../../scripts/harness-dir.sh"
# shellcheck source=../skills/proteger-harness/scripts/harness-dir.sh
source "${0%/*}/../skills/proteger-harness/scripts/harness-dir.sh"
[[ -n "$HARNESS_DIR" ]] || state_unavailable
cd "${HARNESS_DIR%/.harness}" || state_unavailable

Expand Down
13 changes: 5 additions & 8 deletions .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,6 @@
"Edit(./docs/Gerenciador de arquivos.fig)",
"Edit(./.harness/**)",
"Bash(gh pr merge:*)"
],
"ask": [
"Edit(./.github/**)",
"Edit(./.claude/settings.json)",
"Edit(./.claude/hooks/**)",
"Edit(./.claude/agents/**)",
"Edit(./scripts/**)",
"Edit(./.claude/skills/plan-ticket/scripts/**)"
]
},
"hooks": {
Expand All @@ -28,6 +20,11 @@
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/push-verify.sh",
"timeout": 120
},
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/skills/proteger-harness/hooks/state-guard.sh --ajuda 'Se o modo completo travou: pare e peça ao usuário que examine a falha e rode `! scripts/verify.sh unlock` no prompt. Só ele destrava: não destrave nem contorne a trava.'",
"timeout": 10
}
]
},
Expand Down
46 changes: 46 additions & 0 deletions .claude/skills/abrir-frentes/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
name: abrir-frentes
description: "Open the fronts for the tickets of a spec that are ready to start: read the sub-issues and their blocking relations in the issue tracker, pick the frontier (no pending blocker, no front or pull request yet), fit it to the free slots, confirm with the user, create one front per ticket with scripts/frentes.sh novo, and report the folder, the slot and the command that opens the session of each. Use when the user wants to start several tickets of one spec in parallel."
disable-model-invocation: true
---

How to open the parallel fronts of a spec. It prepares the places where the work will happen and stops there: each front gets its own session, and that session plans and implements its ticket. The root `AGENTS.md`, section "Frentes paralelas", owns the rules of a front; `scripts/frentes.sh` owns how one is created and its refusals. This skill reads them and never copies them.

**Input.** The identifier of the spec (the parent issue, `LUI-182`) or of a list of tickets, and optionally how many fronts to open. Without a number, open as many as the free slots allow.

**What it owns.** Choosing which tickets to open and the order. It does not own the slot, the ports, the branch name or the `.env` (that is `scripts/frentes.sh`), nor the planning and implementation of a ticket (that is `/plan-ticket` and `/implement`, run in the session of each front).

**What it never does.**
- Use `--forcar`, or call `remover`. Abandoning a front is the user's.
- Edit a `.env`, a branch or a folder of a front by hand to make a refused `novo` pass.
- Open more fronts than the free slots, or open one without the user's confirmation (step 5).
- Plan or implement a ticket, or start a session in a front. It cannot open a session in another folder, and it tells the user to.
- Change the status of an issue. "In Progress" is moved by the session of the ticket: `/plan-ticket` does it when planning starts, and `/implement` checks it.

## Steps

1. **The tickets of the spec.** Fetch the spec and its sub-issues from the issue tracker, each one with its blocking relations ("blocked by"), its status and its type label. If the user passed tickets instead of a spec, fetch those and their blockers. The dependencies are the native relation of the tracker, not text in the description.

2. **Sort them.** Put each ticket in one group:
- **Done:** leave out.
- **Already taken:** the ticket has a worktree whose branch ends in it (`scripts/frentes.sh listar`), a pull request (open or merged), a local or remote branch (`git fetch`, then `git branch -a --list '*<ticket in lowercase>*'`), or the status "In Progress" or "In Review" in the tracker. Leave out and say where the work is. The `novo` only looks at worktrees: given a ticket that has a branch but no worktree, it would create a second branch for the same ticket, apart from the work already done. How to resume that work is the user's decision. Before calling the work open, check whether it is already in the base: the branch is an ancestor of the base (`git merge-base --is-ancestor <branch> <base>`), or `git cherry <base> <branch>` prints no `+` line, or its pull request is merged. The `git cherry` prints one line per commit of the branch: `+` when the base has no equivalent of it, which is work still pending, and `-` when the base has one, which is work already in the base. A `-` line is not pending work, even though the commit has another hash there. If nothing is pending, the ticket goes to the next group.
- **Stale status:** the tracker says "In Progress" or "In Review" but the work is already in the base. There is nothing to open and nothing to resume. Leave out and tell the user which tickets to close in the tracker, because changing the status is not this skill's job.
- **No code to build:** a ticket that changes nothing in the repository, like a design in Figma, has no pull request and needs no front. Leave out and say so.
- **Blocked:** some blocker is not "Done". Done means merged into the `main`, so a blocker with an open pull request still blocks. Leave out and say what unblocks it.
- **Free:** no pending blocker and not taken. This is the frontier.

If the frontier is empty, say why (everything is blocked, in progress or done) and stop.

3. **How many fit.** Run `scripts/frentes.sh listar` and count the open fronts. The limit is 3 in total (`FRENTES_LIMITE` adjusts it), and the main checkout counts as one whenever it is not on the principal branch (the `main` of the base), a detached HEAD included: at rest it stays on the principal branch, brought up to date with `git merge --ff-only <base>`, and if it is detached or on another branch, say that it takes a slot and how to free it. An old worktree counts too, with or without a pull request: name the ones that look abandoned and leave them to the user, because removing a front without a merge is the user's. The number to open is the least of: the free tickets, the free fronts, and what the user asked for. If it is zero, show the list and stop.

4. **Overlap, and which ones when there are more free tickets than fronts.** Read each free ticket and its section "Decisões de outros tickets", and compare it with the tickets already taken in step 2 whose work is still pending, which keep running while the new fronts work. A ticket with a stale status does not overlap with anything: its work is already in the base the new front starts from. Prefer tickets that touch different areas, because two fronts on the same files meet in a conflict at the sync, and tickets that unblock the most others. Warn when a free ticket overlaps one already taken. Do not pick two tickets where one takes a decision the other also takes: the escalation rule of the root `AGENTS.md` ("Ao trabalhar em um ticket") sends that to the user, so say it. Propose the choice with the reason of each.

5. **Confirm.** Show the proposal: for each ticket, its identifier, title, type (`feature`, or `bugfix` when its label is `Bug`; `hotfix` and `docs` only if the user says) and the slot it will probably take. Say that each front starts a whole Docker environment, which takes minutes. Wait for the user to confirm or change the list. Do not start before.

6. **Create the fronts.** For each confirmed ticket, one after the other, run `scripts/frentes.sh novo <ticket> [type]` in the background (`run_in_background`), because the first start of an environment takes minutes and the commands are not allowed to wait. One after the other, not together: each start builds images and loads the machine. Wait for each to end before the next. If a `novo` refuses (limit, a ticket that already has a front, a port in use on the machine), do not work around it: report the refusal as the script prints it, skip that ticket and go on with the others. If it fails halfway, run `scripts/frentes.sh listar` and say what state the front is in; do not delete anything.

7. **Report.** When all have ended, run `scripts/frentes.sh listar` once and answer in the chat with one row per front: ticket and title, folder, slot and ports, and the command that `novo` printed to open the session. Then, for each ticket, the first thing to run in its session:
- `/plan-ticket <ticket>` when the base has no acceptance file for it (`git show <base>:docs/tickets/<spec>/<ticket>/aceite.md` fails). A new front starts from the base, so this is the usual case.
- `/implement <ticket>` when the base already has the acceptance file, which means the plan is merged. In both cases, the implementation of a planned ticket starts in a new session of the same front.

Close with what was left out and why (blocked tickets and what unblocks them, tickets already in progress, refusals), and with the reminders that matter to several fronts: one browser profile per slot, and `scripts/frentes.sh listar` shows which fronts will conflict.
5 changes: 5 additions & 0 deletions .claude/skills/abrir-frentes/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
interface:
display_name: "Abrir frentes"
short_description: "Open the fronts of the ready tickets of a spec"
policy:
allow_implicit_invocation: false
Loading
Loading