sandcastle-run
Traduire une consigne d'opérateur — « traite le ticket
- License 许可
- Apache-2.0
- 最近更新
- 2026-09-28
- Stars
- ★ 1
- Forks
- 0
01 前言 Front Matter
- name
- sandcastle-run
- description
- Traduire une consigne d'opérateur — « traite le ticket
03 SKILL.md 正文
Lancer une boucle Software Factory
Cette skill ne récite pas les réglages. Elle tient une seule frontière : ce qui
relève de l'identité du projet (.sandcastle/config.ts, réglé une fois, tracé
dans git) et ce qui relève de l'invocation (variables d'environnement du run).
Confondre les deux est l'erreur coûteuse : éditer baseBranch alors qu'il n'y avait
rien à faire, ou coder en dur un numéro de ticket dans l'identité du dépôt.
La table de frontière
| Ce que dit l'humain | Où ça vit | Geste |
|---|---|---|
| « le ticket #42 » | SANDCASTLE_ONLY=42 + label de file |
env + gh issue edit 42 --add-label <label> (ou glab issue update 42 --label <label>) |
| « mode split » / « opus » | SANDCASTLE_PROFILE |
env (défaut split) |
| « chaîné », « empile les MR » | SANDCASTLE_CHAIN=1 |
env (exige un chainableBases non vide dans l'identité) |
| « refais-le », « relance-le » | SANDCASTLE_FORCE=1 |
env — exige SANDCASTLE_ONLY |
| « juste un tour », « n tours » | SANDCASTLE_MAX_ITERATIONS |
env |
| « n tickets à la fois » | SANDCASTLE_MAX_PARALLEL |
env (forcé à 1 en chaîné) |
| « montre-moi d'abord », « à blanc » | SANDCASTLE_DRYRUN=1 |
env |
| « en partant de main », « depuis l'epic » | baseBranch / labelBases |
config.ts, avec confirmation |
gitHost, queueLabels, assignee, mergeStrategy, commitStyle, hooks, report… |
config.ts |
identité — avec confirmation |
Ces sept variables sont l'intégralité de la surface d'invocation : elle est lue en un
seul endroit, loadRunConfig dans .sandcastle/config.ts. Tout le reste est identité.
N'énumère pas les valeurs et les défauts de mémoire. La seule source qui ne mente
jamais est .sandcastle/config.ts et ses commentaires de doc ; lis-le avant de
répondre sur un champ précis.
Le piège n° 1 : SANDCASTLE_ONLY restreint, il n'élargit pas
La file du tour est construite côté hôte depuis queueLabels (host.queueIssues).
SANDCASTLE_ONLY filtre cette file (applyOnly, plan.ts) — il ne va pas
chercher un ticket qui n'y est pas.
Conséquence : SANDCASTLE_ONLY=42 sur un ticket sans label de file donne un
tour vide, sans aucune erreur. C'est le mode d'échec le plus cher en AFK : on part,
on revient, rien ne s'est passé et rien ne l'a dit.
Donc : « traite le ticket #42 » = poser le label de file et restreindre. Les deux.
Procédure
1. Préalables — en lecture seule, sauf le label
Vérifie, nomme ce qui manque avec le geste correspondant, et ne corrige rien :
- Label de file —
gh issue view <n> --json labelscroisé avecqueueLabelsdeconfig.ts. Seule exception à la règle : pose-le. C'est le sens littéral de « traite ce ticket », et un--remove-labell'annule. QuandqueueLabelsen liste plusieurs, prends celui que portent déjà les autres tickets de la file plutôt que le premier de la liste : le dépôt en utilise un en pratique, les autres sont de la compatibilité. - Token de fournisseur — le
tokenKeyde chaque provider du profil actif, dans l'environnement ou dans.sandcastle/.env.secrets. Ne lis jamais la valeur, ne l'affiche jamais : constate la présence de la clé. Le dry-run le dit mieux que toi (requiredTokens, sourceenv/.env.secrets/MISSING). - Hôte authentifié et d'accord avec
origin—gh auth status(ouglab auth status), etgit remote get-url origincohérent avecgitHost. Le dry-run reporte ce désaccord (hostMismatch). - Base à jour — la base locale ne doit pas être en retard sur le remote :
git fetch origin && git status -sb. Un run réel la fast-forwarde lui-même ; le dry-run se contente d'avertir. Le geste, si tu dois le nommer :git fetch origin && git switch <base> && git pull.
Ce qui ne s'automatise pas depuis une skill : authentifier un hôte, écrire un secret. Demande le geste à l'humain.
2. Dry-run — systématique, avant tout lancement réel
SANDCASTLE_DRYRUN=1 SANDCASTLE_ONLY=42 npx tsx .sandcastle/main.ts
Mets les mêmes variables que le run réel : c'est la seule façon de voir le profil, les tokens, les bases, l'état du chaînage et la file tels qu'ils seront. Montre le verdict à l'opérateur. Il lance rien et sort 0 même avec des tokens manquants.
C'est le sens d'« AFK » : ce qui coûte cher n'est pas la minute du dry-run, c'est de partir et de découvrir au retour que le tour était vide ou le profil faux.
3. Lancement — en tâche de fond, sans redemander
Le dry-run a servi de confirmation. Lance, puis donne le chemin du log et la façon de suivre :
mkdir -p .sandcastle/logs
SANDCASTLE_ONLY=42 npx tsx .sandcastle/main.ts > .sandcastle/logs/run-42.log 2>&1 &
tail -f .sandcastle/logs/run-42.log
4. Lire la fin du run — le bloc === Run summary ===
Un run ne se termine plus par « All done » : il imprime des compteurs (itérations
menées, MR publiées, tickets abandonnés) et la cause nommée de chaque abandon
(implementer-failed, no-commits, push-failed, mr-not-opened,
host-unavailable, ou unknown quand le run ne sait pas). Le mode chaîné y est
donné tel qu'il a été appliqué, pas tel qu'il a été demandé.
Le code de sortie porte le même verdict — c'est lui qu'on lit dans un script :
| Code | Verdict | Ce que ça veut dire |
|---|---|---|
0 |
published |
Au moins une MR est ouverte grâce à ce run. |
1 |
sterile |
Le run avait du travail et rien n'en est sorti. Un SANDCASTLE_ONLY qui ne matche rien compte comme du travail : l'opérateur a nommé des tickets et n'en a eu aucun. |
1 |
all-iterations-lost |
Toutes les itérations ont été perdues sur l'hôte. Le code reste 1 même si la reprise du ledger a ouvert la MR d'un run précédent. |
1 |
published, then died |
Le run a publié, puis une panne définitive l'a arrêté. |
2 |
idle |
Il n'y avait rien à faire : la file était vide. Ni échec, ni succès. |
Ne conclus jamais « le run a réussi » sur la seule absence d'erreur dans le log :
lis le verdict. Un 1 sur implementer-failed, host-unavailable ou
all-iterations-lost se relance tel quel ; un 1 sur mr-not-opened ne se
relance pas — la branche est poussée et le run suivant ouvrira la MR manquante
tout seul (relancer dupliquerait le ticket). Un 2 avec SANDCASTLE_ONLY est
impossible : si ton ticket n'a pas été pioché, tu auras un 1 sur
only-no-match, et la cause est presque toujours le label de file manquant.
5. Toute édition de config.ts se fait confirmer
Propose le diff, attends l'accord. L'identité est tracée dans le dépôt du consommateur
et une erreur y contamine tous les runs suivants — pas seulement celui-ci. « En
partant de main » n'est presque jamais une édition : baseBranch vaut déjà main dans
la plupart des instances. Lis avant de proposer.
Ce que cette skill ne fait pas
- Elle ne remplit pas le
CLAUDE.mdni leCONTEXT.mddu projet — ça reste chez le consommateur. - Elle n'authentifie pas l'hôte et n'écrit pas de secret.
- Elle ne récite pas
ProjectConfig: elle renvoie à.sandcastle/config.ts.
04 同仓库更多 Skills
teach
Teach the user a new skill or concept, within this workspace.
handoff
Compact the current conversation into a handoff document for another agent to pick up.
grilling
Grill the user relentlessly about a plan, decision, or idea. Use when the user wants to stress-test their thinking, or uses any 'grill' trigger phrases.
grill-me
A relentless interview to sharpen a plan or design.
wayfinder
Plan a huge chunk of work — more than one agent session can hold — as a shared map of decision tickets on your issue tracker, and resolve them one at a time until the way to the destination is clear.
triage
Move issues and external PRs through a state machine of triage roles — categorise, verify, grill if needed, and write agent-ready briefs.