çµè«
å人ãªãã®CIãã5ã¶æãã£ãšãšã©ãŒã«ãªãããšããªãã£ãã
åªç§ã ã£ããããããªããŠãã©ã転ãã§ã倱æãããããªãæžãæ¹ãããŠããããã
ãã®CIã¯åãæžãããã®ãããªããŠãAIã«äœã£ãŠããã£ãã
ã§ãæ£çŽã«æžããšãã¬ãã¥ãŒããŠéãããšãããããåºãŠãããã®ãçºããŠãã¡ãããšããŠãããã§åãåã£ãã ãã
ããããã®éãGitHub Actions ã®åæ°ã¯æ¶è²»ããç¶ããŠããã
30æ¥ã§çŽ266åããªã«ãæ€ç¥ããªããŸãŸã
æ®æ®µã¯ä»äºã§ã人ãäžããŠãããã®ãã¬ãã¥ãŒããŠæ¿èªããåŽã«ãããã ãã©ããã®åããèªåãAIããåãåããšãã«ã¯æ¿èªãšåŒã¹ãå·¥çšãèžãã§ããªãã£ãã
ã ããããã¯CIã®ãã°ã®è©±ãããªããŠãæ¿èªã®äºæ
ã®è©±ã
äœãåããŠããã
gtd/ ãš zettelkasten/ é
äžã® Markdown ã« YAML frontmatter ããããããpush ãš PR ã®ãã³ã«å
šä»¶ãã§ãã¯ãã stepã
å®ç©ãããã
- name: YAML frontmatter ã®ååšãã§ãã¯
run: |
echo "=== frontmatter ãã§ã㯠==="
errors=0
while IFS= read -r file; do
head -1 "$file" | grep -q '^---' || {
echo "â frontmatter ãèŠã€ãããŸãã: $file"
errors=$((errors + 1))
}
done < <(find gtd/ zettelkasten/ -name '*.md' -not -name '.gitkeep' 2>/dev/null)
if [ "$errors" -eq 0 ]; then
echo "â å
šãã¡ã€ã«ã« frontmatter ããããŸã"
else
echo "â ${errors} ãã¡ã€ã«ã« frontmatter ããããŸãã"
fi
å
ã«èšã£ãŠãããšãåã¯ãããèªåã§èªãã§æ°ã¥ãããããããªã
ãâåã¯ã³ãŒããæžããªãåŽã®äººéã§ãæ£çŽããã®ãœãŒã¹ãæž¡ãããŠçºããŠãèŠã€ããããªãã£ããšæã
æ°ã¥ããã®ã¯5ã¶æçµã£ãŠãããCI ããŸãããš Claude ãšèŠçŽããŠããŠãClaude ã«èŠã€ããŠããã£ãã
ãã® step ã«ã¯ exit 1 ããªãã
errors ãæ°ããŠãéåãã¡ã€ã«åãåºããŠãä»¶æ°ãåºããŠãæåãšå€±æã§åå²ãŸã§ããŠããã
ãã®ããã§äœãè¿ããŠãªãããããã® step ã¯çµ¶å¯Ÿã«æåããã
ããã«åã workflow ã®ãªã³ã¯ãã§ã㯠step ã«ã¯ continue-on-error: true ãä»ããŠããã
ã€ãŸããã® workflow ã¯ãã©ããªéåããã£ãŠã倱æã«ãªããªããŠãæ€ç¥ã§ãšã©ãŒã«ãªã£ãããšã¯5ã¶æéã§äžåºŠããªãã
ã§ãå®éã« frontmatter ãæ¬ ãããã¡ã€ã«ã1ä»¶ã2ã¶æåèŠéãããŠããã
CIã¯æ¯åãããæ€åºããŠããã°ã« â ãåºããŠãæåã§çµãã£ãŠããã
ãªãåã¯çããªãã£ãã®ã
ãããæ¬é¡ã§ã3ã€ãããšæã£ãŠããã
1. å ±åã®åœ¢ãæŽã£ãŠããããã
ãã®CIã«ã¯ãšã©ãŒã«ãŠã³ã¿ãããããéåãããã¡ã€ã«åãåºãããæåãšå€±æã§åå²ãããŠãããèŠåã®çµµæåãŸã§ä»ããŠãã
ãâã£ãŠããœãŒã¹ãèªãã§ç¢ºããããããããªã
ãâäœã£ãŠããã£ããšãã« AI ãããå ±åããŠããŠãå®éãã°ã«ããã®ãšããåºãŠãã
ã§ãå ±åã¯åãããªããŠãã«ãŠã³ã¿ãåå²ãèŠåãæ¬åœã«å
šéšããã
ãªãã£ãã®ã¯ exit 1 ã ãã
ãã£ãŠãããšã®åæãå
šéšæ¬åœã§ããå¹ããŠããã©ããã¯å¥ã ã£ããã ããã
å ±åã®åœ¢ãæŽã£ãŠããšã人éã¯ãã¡ãããšããŠãããã§åãåã£ã¡ãããã ãããããã5ç§ã§ã
å¹ããŠããã©ããã¯å ±åããã¯åãããªããŠã倱æãããã©ããã§ããåãããªãã
AIãäœã£ããã®ã¯ãããåä»ã§ã圢ãšå ±åã ãã¯çµ¶å¯Ÿã«åŽ©ããªãã
ã ãã圢ã§åãåãã®ãäžçªå±ãªã
ãâ人éãæãæããä»äºã¯ãã³ãŒããå ±åãã©ãã厩ããããäžå¿åŒã£ããã
ãâAIã¯åŽ©ããªã
2. ãã£ãšæåããŠããããã
åœããåã ãã©ãæžããŠãã䟡å€ããã£ãŠãæåãç¶ããŠãããåé¡ãªããã ãš5ã¶ææã£ãŠãã
ã§ãCIã®ãæåãã£ãŠãèœã¡ãæ¡ä»¶ãã²ãšã€ãæžããŠãªããŠãåºããããæ€æ»ããŠåé¡ãªããªã®ããããããæ€æ»ããŠãªãã®ããçµæã ãããåºå¥ãã€ããªãã
3. ããã°ã«ã¯èŠåãåºãŠãŸããã§æºè¶³ããããã
ããããã¡ã°ãåä»ã§ããã®CIãéåãæ€åºããŠããã¡ã€ã«åãåºããŠãèŠåãããŠãä»äºã¯ããŠããã ããã
ã§ããæåã®ãã°ãªããŠæ®éèŠãªããããç¬
ããã ãããèŠéãããã£ãŠããã®ãæ£ç¢ºãããªããªãåºããã£ãŠèŠãŠãªããã ãããèŠéããäœããªãã
ããã°ã«åºããããŽãŒã«ã«ãªã£ãŠãèšèšãåãåã£ãæç¹ã§ããããªãã®ã¯æ±ºãŸã£ãŠãã
ãã°ã£ãŠãèœã¡ãŠéç¥ãæ¥ãŠåããŠéããã®ã ãã
åãåããšãã«èãã¹ã質åã¯ãã²ãšã€ã ãã ã£ãã
ãããæ¬åœã«èœã¡ãã®ãïŒ
èããŠãªãã£ããã»ã»ã»
ããã«æªãããšãéäžã§äžåºŠãæãå ¥ããŠãã
çŽ4ã¶æç®ã«ããã® workflow ãè§Šã£ãŠããã
çç±ã¯ãActions ã®åæ°ãé£ããããŠãããã
Claude ã«é Œãã§ããªã³ã¯ãã§ãã¯ã鱿¬¡åããŠãconcurrency ã§äºéå®è¡ãæ¢ããã
åæ°ã¯æžã£ããã广ã¯ãã£ãã
ã§ãè§Šã£ãã®ã¯ãªã³ã¯ãã§ãã¯ã®ã»ãã ãã§ãpush ããšã«èµ°ã frontmatter ãã§ãã¯ïŒãªã«ãæ€ç¥ããŠãªãåŽïŒã¯ããã®ãŸãŸæ®ããã
ãæ¶è²»ãå€ããã»ãã¯æ²»ã£ãŠãããªã«ãæ€ç¥ããŠãªããã»ãã¯ãã®ãŸãŸæ®ã£ãã
ããããCIã¯èŠçŽããããšããèšæ¶ã ããæ®ãã®ã§ã次ã«çãæ©äŒãŸã§é ã®ãã
ãããäžçªã®æèšã ãšæã£ãŠãŠãã³ã¹ããæ°ã«ãªã£ãŠè§Šã£ãŠããšãã¯ãã³ã¹ãããèŠãŠãªãã
è§Šãã€ãã§ã«ãããã¯äœãæ€åºããŠãã®ãããæ€åºãããäœãèµ·ããã®ããã1å声ã«åºãã°ããã£ããã ãã©ã
ã©ãçŽããã
ãããåãæãåããããããããªããŠãClaude ãšå£æã¡ããŠæ±ºããã
CI ãçŽãããããªããŠ3å±€ã«å²ãçŽãããšã«ããŠãã³ãŒã㯠Claude ãæžããã
ã¡ãªã¿ã« hook ã®ååšèªäœã¯åããç¥ã£ãŠãŠãã¡ãããšçè§£ããŠãªããŠäœ¿ããŠãªãã£ãã ãã
䜿ããããã«ãªã£ãèµ·ç¹ã¯äŒç€Ÿã®AIå匷äŒ
ãâè¥æãšè©±ããŠããŠã仿§é§åéçºããã³ã³ããã¹ããšã³ãžãã¢ãªã³ã°ããã«ãŒããšã³ãžãã¢ãªã³ã°ããšãã3ã€ã®èšèãåºãŠããŠãèªåããã£ãŠãããšãšã®å¯Ÿæ¯ãèããæ¹ããããªãšæã£ã
ãã®æ¥ã®ãã¡ã« Claude ãšèª¿ã¹ãŠèªåã®ãªãã«åœãŠã¯ããŠããææžã®ãé¡ãã hook ã®ä¿èšŒã«å€ãããã§6æ¬ãŸãšããŠå
¥ããŠã調ã¹ãçµæã¯ãã©ã€ãã«ããŠã¡ã³ããŒã«ãé
ã£ãã
ä»åã® frontmatter ãã§ãã¯ã¯ããã®å»¶é·ã®12æ¬ç®
ãâè¥æãšåãç®ç·ã§å匷äŒã«æ··ãã£ãŠãæŸã£ãèšèãã¹ããæéã§èª¿ã¹ãŠèªåã®é ã«èœãšããŠããŸãšããŠå
±æãã
ãâããããããšãããã®ã倧äºãªãã ãšæããåãã®å±€ãšããŠ
ã ããä»åã®ã¯ãå匷äŒã®æµãã§åŠãã ä»çµã¿ãããã®äºæ ã«ãåœãŠãã ãã
1. æ€èšŒã¯æå ã® hook ã«ç§»ã
frontmatter ãã§ãã¯ã¯ Node ã®ã¹ã¯ãªããã«ããŠãClaude Code ã® PostToolUse hook ããåŒã¶ããã«ããã
ãã¡ã€ã«ãæžããçŽåŸã«å€å®ããŠãéåãªã decision: "block" ãè¿ãã
èŠç¹ã ãæç²ãããšããã
// å€å®ã¯éå§ --- ãšéã --- ã®æç¡ã ããå°ããåçŽã«
function violationOf(absPath) {
const lines = fs.readFileSync(absPath, 'utf8').split(/\r?\n/);
if (lines[0] !== '---') return 'frontmatter ãç¡ãïŒ1è¡ç®ã --- ã§ãªãïŒ';
for (let i = 1; i < lines.length; i++) {
if (lines[i] === '---') return null; // éããããã° OK
}
return 'frontmatter ãéããŠããªãïŒéã --- ãç¡ãïŒ';
}
// éåãªã echo ãããªã block ãè¿ããæžããæ¬äººïŒAIïŒã®æãæ¢ãŸã
process.stdout.write(JSON.stringify({
decision: 'block',
reason: `[frontmatter] ${relPosix}: ${why} â å
é ã« --- ã§å²ãã frontmatter ã远å ããããš`,
}) + '\n');
CIãšæ¯ã¹ãå©ç¹ã¯3ã€ã
-
éã
ãâpush ãåŸ ããªã
-
ãã®å Žã§çŽãã
ãâAIãèªåã§çŽã
ããâæžã蟌ã¿èªäœã¯æåããŠãã®ã§å®å®³ããªã -
exitã®æžãå¿ããèµ·ãã«ãããâhook ã¯ãããã¯ãä»äºãªã®ã§ãè¿ãå€ãæžãå¿ãããåããªãããšã«ããæ°ã¥ã
2. ç¶²ã¯é±æ¬¡ã¹ã€ãŒãã«æ®ã
hook ã¯ããŒã«ã«ã®ã»ãã·ã§ã³ããéããªã
ãâWebçãã¹ããçµç±ã®æžã蟌ã¿ã¯çŽ éããã
ã ããåãã¹ã¯ãªããã --all ã§å
šä»¶èµ°ããã鱿¬¡ workflow ãå¥ã«çšæããŠããã£ã¡ã¯éåãããã° exit 1 ããïŒä»åºŠããïŒã
圹å²åæ ãšããŠã¯ãhook ããéããã©æŒãããåŽã§ã鱿¬¡ã¹ã€ãŒãããé ããã©æŒããªããåŽã
3. CIã«ã¯ãèœã¡ãŠåããŠæ°ã¥ãããã®ãã ãæ®ã
CIã¯å€éšãªã³ã¯åããã§ãã¯å°çšã«ããŠãcontinue-on-error ãå€ããã
workflow ã®ã³ã¡ã³ãã«ã¯ããæžããã
# continue-on-error ã¯ä»ããªã: èœã¡ãŠåããŠæ°ã¥ããïŒActions ã®å€±æéç¥ãå¯äžã®å°ç·ïŒã
éç¥ãæ¥ãªããã§ãã¯ã¯ãç¡ãã®ãšåãã ã£ãã
æåã®ãã°ã¯èª°ãèªãŸãªãïŒåã¯5ã¶æèªãŸãªãã£ãïŒããããšã©ãŒã§èœã¡ã以å€ã«äŒããéããªãã
æ¿èªããåŽãšããŠã次ããäœãèŠãã
èªåã®ãªãã®è©±ãšããŠæžããŠãããã©ããã¶ãããããå¢ããã®ã¯ãéšäžããAIã«æžãããŸããããšæã£ãŠãããã®ãéããã©ããã®å Žé¢ã ãšæã£ãŠããã
åãå®¶ã§ãã£ãçŽ éãããä»åºŠã¯ä»äºã§ããããšã«ãªãã
åãçœ ã«ããããåœ¢ã¯æŽã£ãŠãããã
ã ãããã³ãŒãã®äžèº«ãèªãã®ã¯ãããŠãèãããšã3ã€ã«æ±ºããã
-
ããã¯äœãæ€åºããã®ã
ãâäžèšã§èšããªããªãããã¶ããŸã èšèšãããŠãªã
-
æ€åºãããäœãèµ·ããã®ã
ãâããã°ã«åºãŸããã¯çãã«ãªã£ãŠãªã
ããâ誰ã®ç®ã«ãã©ããã圢ã§å ¥ãã®ã -
ãããšéåãããã®ãèŠãã
ãâèŠãŠãªããã°ããã®ãã§ãã¯ã¯æªæ€èšŒ
3ã€ãšããææç©ãèªãŸãã«èããã
åãã®å±€ã¯æéçã«ããã©ã³ã¯çã«ãããœãŒã¹ãèªã¿åãããã埮åŠãªã©ã€ã³ã ããèªãã ãèªãã ã§åœ¢ã«åŒã£ããããããèªãŸãã«èãã
å·®ãæ»ããšãããã³ãŒããæªãããããªããŠããããšèœãšããŠèŠããŠãã§æžãããAIãæžãããã©ããã«é¢ä¿ãªãå¹ããããèšãæ¹ãšããŠæããªãã
ãšããããããæžããŠãŠæ°ã¥ãããã©ãæ°ãã話ãããªãã£ãã
決æžç³»ã®ã·ã¹ãã ãäœããšããããã©ã€ãã®ããã¥ã¢ã«ïŒäžè¬çã«ã¯ãšã©ãŒå¯Ÿå¿ããã¥ã¢ã«ããªïŒãæžãã®ãšãã£ãšåãã
ãâäœãæ€ç¥ãããã®ã
ãâæ¬åœã«ãšã©ãŒãšããŠæ€ç¥ããå¿
èŠãããã®ã
ããâãªãã©ã€ããã ããªã®ããåæäœããã ããªã®ã
ãâæ€ç¥ããŠäœããããã®ããããŠã»ããã®ã
ãâ誰ãããã®ããã§ããã®ã
ãâã·ã¹ãã ã®ç¹æ§ã»èŠæš¡ã»ä»çµã¿ã«åãããŠèããŠãå¿
ã詊éšã§ããããæ€ç¥ããŠå¯Ÿå¿ããããšãããŸã§è©Šéšãã
ã§ããããå¿
ãéçºããŠãã¿ããªãšäŒè©±ããŠæ±ºããã
ãäºãã®æå³ãçè§£ãåã£ãŠãåãç®ç·ã§è©±ãåã£ãŠãæåŸã¯åãèŠæããã
ã¬ãã¥ãŒãšããããèªèåããã
åãã³ãŒããèªããªããŠãä»äºã«ãªã£ãŠãã®ã¯ããã¶ãããããã£ãŠãããã ã
AIãçžæã«ãªã£ãŠããã®äŒè©±ãçç¥ããããããä»åã®äºæ ãªãã ãšæãã
æèšïŒèªåçšã®ã¡ã¢ïŒ
-
echoããã ãã®ãã§ãã¯ã¯ããã§ãã¯ã§ã¯ãªããâexit code ãè¿ããªãæ€èšŒã¯ãæ€èšŒããŠãããã«èŠããã ã
-
AIãäœã£ããã®ã¯ã圢ãšå ±åãæŽã£ãŠãããã ããåãåã£ãŠããŸã
ãâã«ãŠã³ã¿ãåå²ãèŠåæããæ¬åœã«ãã
ãâ圢ãšå¹åã¯å¥ç© -
CIãå ¥ããããäžåºŠãããšéåãäœã£ãŠãã¡ãããšãšã©ãŒã«ãªãã®ãèŠã
ãâåã¯ããããã£ãŠãªããŠã1åã§æžãã®ã«5ã¶æå€±ã£ã
-
continue-on-errorã¯ãã§ãã¯ã食ãã«å€ãããâä»ãããªããèœã¡ãŠãæ§ããªãçç±ããã³ã¡ã³ãã«æ®ã
仿¥ã§ããããšïŒ1åïŒ
èªåã®CIã§ããããšéåã1ä»¶äœã£ãŠ push ããŠã¿ãã
ã¡ãããšãšã©ãŒã«ãªããã
ãâyml ãèªããªããŠããAI ã«ããã®ãã§ãã¯ã«ãããšåŒã£ãããéåãäœã£ãŠããšé Œãã°ã§ãã
ãšã©ãŒã«ãªããªãã£ããããã®ãã§ãã¯ã¯åããŠãªããããexit 1 ã1è¡è¶³ããã
åã¯ããããããªããŸãŸ5ã¶ææãç¶ããŠã266åãäœã®åœ¹ã«ãç«ã£ãŠãªãã£ããç¬