Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

dancinlab/harness

Repository files navigation

harness

ํ”„๋กœ์ ํŠธ ๋ฌด๊ด€(project-agnostic) AI ์ฝ”๋”ฉ ํ•˜๋„ค์Šค โ€” ์–ด๋А repo ์—๋“  ๋“œ๋กญ์ธ. ์‹คํ–‰ยทํŒŒ์ผยทํ”„๋กฌํ”„ํŠธ ๋‹จ๊ณ„์— ๋ผ์–ด๋“ค์–ด ๊ทœ์น™์„ ๊ฐ•์ œํ•˜๊ณ , ๋ชจ๋“  ๊ฒฐ๊ณผ๋ฅผ append-only JSONL ๋กœ ๋‚จ๊ธด๋‹ค.

๐Ÿ”ง ํ•˜๋„ค์Šค = "AI ์ฝ”๋”ฉ ๋ณด์•ˆ๊ฒ€์ƒ‰๋Œ€" โ€” AI ์—์ด์ „ํŠธ(Claude Code / Codex ๋“ฑ)๊ฐ€ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜ ํŒŒ์ผ์„ ๊ณ ์น˜๊ธฐ ์ง์ „ยท์งํ›„์— ๊ฒŒ์ดํŠธ๋ฅผ ํ†ต๊ณผ์‹œ์ผœ, ์œ„ํ—˜ํ•œ ๋™์ž‘์€ ๋ง‰๊ณ (block) ์ž ๊ธˆ ํŒŒ์ผ ์ˆ˜์ •์€ ๊ฒฝ๊ณ (warn)ํ•˜๋ฉฐ ๊ฒ€์ฆยท์ธ๊ณ„๋ฅผ ์ž๋™ํ™”ํ•œ๋‹ค. ESLint ๊ฐ€ "์ฝ”๋“œ ๋ฌธ๋ฒ•"๋งŒ ๋ณธ๋‹ค๋ฉด, ํ•˜๋„ค์Šค๋Š” ๋ช…๋ น ์‹คํ–‰ยทํŒŒ์ผ ์ž ๊ธˆยท๊ฒ€์ฆยท์„ธ์…˜ ์ธ๊ณ„๊นŒ์ง€ ์ž‘์—… ํ๋ฆ„ ์ „์ฒด๋ฅผ ๋‹จ์†ํ•œ๋‹ค.

์ด ์ €์žฅ์†Œ๋Š” dancinlab ์˜ ๋ชจ๋“  repo(edge ยท anima ยท ...)๊ฐ€ ๊ณต์œ ํ•˜๋Š” ์—”์ง„์ด๋‹ค. ํ”„๋กœ์ ํŠธ๋งˆ๋‹ค ๋‹ฌ๋ผ์ง€๋Š” ๊ฒƒ์€ harness.config.json + .harness/*.json(๊ทœ์น™ ๋ฐ์ดํ„ฐ)๋ฟ์ด๊ณ , .ts ์—”์ง„ ์ฝ”๋“œ๋Š” ์ „๋ถ€ ๊ณต์œ ํ•œ๋‹ค.

๐ŸŒ ์–ธ์–ด ๋ฌด๊ด€: ์›น๋ฟ ์•„๋‹ˆ๋ผ Python ยท Rust ยท C/C++ ยท Go ยท Swift ยท hexa ๋กœ์ปฌ/๋ชจ๋ฐ”์ผ ์•ฑ์—๋„ ์“ด๋‹ค. init ์ด ์Šคํƒ์„ ๊ฐ์ง€ํ•ด ๊ฒ€์ฆ ๋ช…๋ น(cargo/pytest/swift build/...)๊ณผ ๋‹ค๊ตญ์–ด ์šฐํšŒํŒจํ„ด(# type: ignoreยท#[allow]ยทswiftlint:disable...)์„ ์ž๋™ ์ ์šฉ. ์—”์ง„ ์‹คํ–‰์— ๊ฐœ๋ฐœ๋จธ์‹  Node 1๊ฐœ๋งŒ ํ•„์š”(ํƒ€๊นƒ ๋นŒ๋“œ์™€ ๋ฌด๊ด€). โ†’ docs/languages.md

[ edge repo ]โ”€โ”€โ”
[ anima repo ]โ”€โ”ผโ”€โ”€โ–ถ ๊ฐ™์€ .ts ์—”์ง„ (์ด repo)
[ ๋‹ค๋ฅธ repo ]โ”€โ”€โ”˜ โ–ฒใ•ใ‚“ใ‹ใ
 โ”‚ ๊ฐ์ž harness.config.json + .harness/*.json ์œผ๋กœ
 โ””โ”€ ๊ทœ์น™๋งŒ ๋‹ค๋ฅด๊ฒŒ ์ฃผ์ž…

์„ค๊ณ„ ์›์น™ (H1โ€“H5)

# ์›์น™ ์˜๋ฏธ
H1 ์„ฑ๊ณต์€ ์กฐ์šฉ, ์‹คํŒจ๋Š” ์‹œ๋„๋Ÿฝ๊ฒŒ ํ†ต๊ณผ ์‹œ stdout ์นจ๋ฌต, ์‹คํŒจ๋งŒ stderr (JSON)
H2 ์ž๋™ ์ˆ˜์ • ์•ˆ ํ•จ ์ œ์•ˆยท์ฐจ๋‹จยท๊ฒฝ๊ณ ๋งŒ. ๊ณ ์น˜๋Š” ๊ฑด ์‚ฌ๋žŒ/์—์ด์ „ํŠธ
H3 bitter-gate ์ƒˆ ๊ทœ์น™ ์ถ”๊ฐ€ ์ „, ์•ˆ ์“ฐ๋Š”(dormant) ๊ทœ์น™ ๋จผ์ € ํ๊ธฐ
H4 config ์ฃผ๋„ ๋ชจ๋“  ํ”„๋กœ์ ํŠธ ์ƒ‰์ฑ„๋Š” ๋ฐ์ดํ„ฐ(JSON)๋กœ. ์—”์ง„ ์ฝ”๋“œ๋Š” ๋ถˆ๋ณ€
H5 AI-native ๋ชจ๋“  ์‚ฐ์ถœ๋ฌผ JSONL append-only (.harness/logs/*.jsonl)

๊ตฌ์กฐ

harness/
โ”œโ”€โ”€ bin/harness ์‹คํ–‰ ์ž…๊ตฌ (bash โ€” tsx ๋Ÿฐํƒ€์ž„ ์ž๋™ํƒ์ƒ‰)
โ”œโ”€โ”€ cli/index.ts ๋””์ŠคํŒจ์ฒ˜ (harness lint โ†’ lint.ts)
โ”œโ”€โ”€ lib/ ๊ณต์šฉ ๋ถ€ํ’ˆ
โ”‚ โ”œโ”€โ”€ paths.ts repo-root ์ž๋™ํƒ์ƒ‰ (harness.config.json / .git ์ƒํ–ฅ ํƒ์ƒ‰)
โ”‚ โ”œโ”€โ”€ config.ts harness.config.json ๋กœ๋“œ + ๊ธฐ๋ณธ๊ฐ’ ๋จธ์ง€
โ”‚ โ”œโ”€โ”€ lockdown.ts L0(์ž ๊ธˆ) ํŒŒ์ผ ๋ชฉ๋ก (config + ๐Ÿ”ด ๋งˆํฌ๋‹ค์šด ๋ธ”๋ก ํŒŒ์‹ฑ)
โ”‚ โ”œโ”€โ”€ log.ts json.ts exec.ts
โ”œโ”€โ”€ modules/ ๊ธฐ๋Šฅ 12์ข… (์•„๋ž˜ ํ‘œ)
โ”œโ”€โ”€ config/ ๋ฒˆ๋“ค ๊ธฐ๋ณธ ๊ทœ์น™ (๋„๋ฉ”์ธ-๋ฌด๊ด€)
โ”‚ โ”œโ”€โ”€ enforcement.json ์‹คํ–‰/์“ฐ๊ธฐ ์ฐจ๋‹จ ๊ทœ์น™ + ํ”„๋กฌํ”„ํŠธ ํžŒํŠธ
โ”‚ โ”œโ”€โ”€ keywords.json ํ”„๋กฌํ”„ํŠธ ํ‚ค์›Œ๋“œ ํŠธ๋ฆฌ๊ฑฐ
โ”‚ โ””โ”€โ”€ severity-map.json ์˜ค๋ฅ˜ severity ๋ถ„๋ฅ˜
โ””โ”€โ”€ harness.config.example.json

๋ช…๋ น (modules)

๋ช…๋ น ์—ญํ•  hook ๋‹จ๊ณ„
pre bash / pre write ์ฝ”๋“œ๋ ˆ๋ฒจ ๊ฐ€๋“œ(force-push{blind --force/-f/+refspec ์ฐจ๋‹จ ยท --force-with-lease๋Š” ํ—ˆ์šฉ ยท # force-ok ์˜ˆ์™ธ} ยท cloud-raw c11 ยท poll c19 ยท danger{--no-verifyยทreset --hardยทcurl|sh ๋Š” ์ƒ์‹œ always-on ยท rm -rf ๋ฃจํŠธ(/ยท/*ยท~ยท$HOMEยท*)๋Š” config dangerGuard.rmRfRoot ํ† ๊ธ€ ยท ๊ธฐ๋ณธ OFF(opt-out)} ยท secret-literal c1 ยท handoff-scatter) โ†’ ๊ทธ๋‹ค์Œ config enforcement ์ •๊ทœ์‹. ์ฝ”๋“œ ๊ฐ€๋“œ๋Š” config๋ณด๋‹ค ๋จผ์ € ์‹คํ–‰(profile ํŽธ์ง‘ ๋ฌด๋ ฅํ™” ๋ฐฉ์ง€) ยท ์ธ๋ผ์ธ # ...-ok/// @secret-ok ๋งˆ์ปค + dangerGuard.rmRfRoot ํ† ๊ธ€๋งŒ ์˜ˆ์™ธ PreToolUse
post bash <exit> / post edit <file> ๊ฒฐ๊ณผ ๊ธฐ๋ก, 0โ‰ exit ๋ผ์šฐํŒ…, L0 ํŽธ์ง‘ ๊ฒฝ๊ณ  PostToolUse
prompt <text> ํ‚ค์›Œ๋“œ ํŠธ๋ฆฌ๊ฑฐ + ํ”„๋กฌํ”„ํŠธ ํžŒํŠธ ์ฃผ์ž… UserPromptSubmit
architecture {inject|show} repo-root ARCHITECTURE.json(์šฐ์„ )/.md ๋ฅผ ์ปจํ…์ŠคํŠธ๋กœ ์ฃผ์ž… โ€” CLAUDE.md ์ฒ˜๋Ÿผ ์„ค๊ณ„ SSOT ์ƒ์ฃผ (80KB ์ดˆ๊ณผ ์‹œ ์ ˆ๋‹จ, ๋ถ€์žฌ ์‹œ ๋ฌด์Œ) SessionStart + ๋งค UserPromptSubmit
claudemd {inject|show} repo-root CLAUDE.md(ํ”„๋กœ์ ํŠธ ๊ทœ์น™)๋ฅผ ๋งค ํ„ด ์žฌ์ฃผ์ž… โ€” commons ์ฒ˜๋Ÿผ salience ์œ ์ง€ํ•ด ๊ทœ์น™์ด ๋ฌปํžˆ์ง€ ์•Š๊ฒŒ (์„ ํƒ์  <!-- enforce:start/end --> ๋ธ”๋ก๋งŒ, 80KB ์ ˆ๋‹จ, ๋ถ€์žฌ ์‹œ ๋ฌด์Œ) UserPromptSubmit
lint [all|fast] staged-L0 + ์‹ ์„ ๋„ + CHANGELOG ๋ˆ„๋ฝ + ์ˆ˜๋ ด ๋ˆ„๋ฝ ์ฒดํฌ commit ์ „ (git pre-commit hook)
ci [all|fast|list] config ์˜ ๊ฒ€์ฆ ๋ช…๋ น ๋ณ‘๋ ฌ ์‹คํ–‰ (์‹คํŒจ 1๊ฐœ๋ผ๋„ โ†’ exit 1; ์˜› ์ด๋ฆ„ verify ๋ณ„์นญ ์œ ์ง€, config ํ‚ค๋„ verify.checks) commit/push ์ „
ci-track <pr|branch> [--watch] [--merge-on-green] [-R owner/repo] ์›๊ฒฉ PR/CI ์ฒดํฌ ์ถ”์  โ€” gh pr checks --json โ†’ pass/fail/pending ์ง‘๊ณ„ + ๐ŸŸขGREEN/๐Ÿ”ดRED/๐ŸŸกPENDING/โšชNONE verdict(exit 0/2/1/0). --watch = CLI-๋‚ด๋ถ€ ํด๋ง์œผ๋กœ terminal ๊นŒ์ง€ ๋Œ€๊ธฐ(์†์ˆ˜ ์ง  gh pr checks|grep + /tmp monitor sleep ๋ฃจํ”„ ๋Œ€์ฒด ยท c19), --merge-on-green = ๊ทธ๋ฆฐ์ด๋ฉด ์ž๋™ squash-merge merge-on-green ยท CI ๋Œ€๊ธฐ ์‹œ
worktree {scan|gc|guard <cmd>} no-pileup ๊ฐ•์ œ โ€” scan=stranded(๋ฏธ์ปค๋ฐ‹/๋ฏธํ‘ธ์‹œ) ์›ŒํฌํŠธ๋ฆฌ ์ ๋ฐœ(exit 1 ๊ฒŒ์ดํŠธ) ยท gc=agent ์›ŒํฌํŠธ๋ฆฌ ์ž๋™ ์ˆ˜๊ฑฐ: [gone] ๋จธ์ง€๋ถ„ + age ๋ฐฑ์Šคํ†ฑ(HEAD>worktree.maxAgeDays ๊ธฐ๋ณธ 3์ผ โ†’ ๋ฏธํ‘ธ์‹œ ํŒ์€ refs/reaped/<br> ๋ณด์กด ํ›„ reap). dirty/locked/recent(<1h)๋Š” ์ ˆ๋Œ€ ์•ˆ ๊ฑด๋“œ๋ฆผ. squash-mergeยทno-push ๋กœ [gone] ์•ˆ ๋œจ๋Š” fleet ์›ŒํฌํŠธ๋ฆฌ ๋ˆ„์ ์„ ๋ง‰์Œ SessionStart
errors {route|list|drain_check|mark_fixed} ์˜ค๋ฅ˜ severity ๋ถ„๋ฅ˜ + ํ ์ƒ์‹œ
ledger {register|complete|list|gc|dup_check} ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์—์ด์ „ํŠธ ์ž‘์—… ๋“ฑ๋ก(์ค‘๋ณต ๋ฐฉ์ง€) Agent ์ „/ํ›„
bitter-gate audit [window] ๊ทœ์น™ ํžˆํŠธ ๋นˆ๋„ โ†’ dormant ๊ทœ์น™ ํ๊ธฐ ๊ฒ€ํ†  ๊ทœ์น™ ์ถ”๊ฐ€ ์ „
audit [full|summary|json] 6์ถ• ์ž๊ฐ€ ์Šค์ฝ”์–ด์นด๋“œ (/60) ์ฃผ๊ธฐ์ 
gc [scan|drift] ๊ฐ€์ด๋“œ ๋งˆํฌ๋‹ค์šด์˜ ๊นจ์ง„ ๋งํฌ ํƒ์ง€ ์ฃผ๊ธฐ์ 
folders [scan|scaffold <dir>] ์„œ๋ธŒํด๋”๋ณ„ CLAUDE.md ๋ˆ„๋ฝ ํƒ์ง€ + ํ…œํ”Œ๋ฆฟ ์ƒ์„ฑ (ํŽธ์ง‘ ์‹œ ์ž๋™ ๋„›์ง€) ์ฃผ๊ธฐ์ /์ž‘์—… ์ค‘
convergence {status|recompute|by-category|scan|due-check} incident ์ˆ˜๋ ด ์ถ”์  + scan = ์ธ๋ผ์ธ @convergence ์žฌ๋ฐœ๋ฐฉ์ง€ ๋งˆ์ปค(c1) ๊ฒ€์ฆ(ํ•„์ˆ˜ํ‚ค stateยทid + state enum) โ€” harness lint ๊ฐ€ ํ˜ธ์ถœํ•ด ๋ถˆ๋Ÿ‰์„ CONVERGENCE-MALFORMED(block)๋กœ ์ปค๋ฐ‹ ์ฐจ๋‹จ. ์žฌ๋ฐœ ์‹ ํ˜ธ(์žฌ๋ฐœยทstaleยทregressionยทagain...)๋Š” keyword ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ โŸฆCONVERGENCE-DUE id=...โŸง ์บก์ฒ˜ ํ† ํฐ+๋ถ€์ฑ„ ์ถœ๋ ฅ โ†’ well-formed ๋งˆ์ปค ์ž‘์„ฑ ์‹œ post-edit ์ž๋™ ํ•ด์†Œ, ๋ฏธํ•ด์†Œ๋ฉด due-check ๊ฐ€ Stop ์—์„œ 1ํšŒ ํ™˜๊ธฐ(warn-only) ๋ฒ„๊ทธ ์ˆ˜์ • ํ›„ ยท commit
sync {run|diff} (์„ ํƒ) repo ์ž์ฒด ๊ณต์œ ํŒŒ์ผ sync ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰ ๊ณต์œ ํŒŒ์ผ ๋ณ€๊ฒฝ ํ›„
pool {list|add|rm|on <h> <cmd>|status|specs [h]} ํ˜ธ์ŠคํŠธ ๋กœ์Šคํ„ฐ + ์›๊ฒฉ ์‹คํ–‰. shared:false ํ˜ธ์ŠคํŠธ๋Š” ์ œํ•œ ํ˜ธ์ŠคํŠธ โ€” allow ํ”„๋กœ์ ํŠธ ์ปจํ…์ŠคํŠธ ๋ฐ–์—์„  on ์ฐจ๋‹จ(๊ณต์šฉ ์ปดํ“จํŠธ๋กœ ๋ชป ์”€). on ์€ ssh ๋ฅผ ์ง์ ‘ spawn(argv)ํ•ด cmd ์˜ $/$(...) ๊ฐ€ ๋กœ์ปฌ์ด ์•„๋‹ˆ๋ผ ์›๊ฒฉ ์…ธ์—์„œ ์ „๊ฐœ๋จ. specs ๋Š” ํ˜ธ์ŠคํŠธ๋ณ„ ์ฝ”์–ด/๋ฉ”๋ชจ๋ฆฌ/GPU ๋ฅผ ssh ํ”„๋กœ๋ธŒํ•ด ๋กœ์Šคํ„ฐ์— ์บ์‹œ(listยทstatus ์— ใ€ˆ12c ยท 30G ยท GPU:...ใ€‰ ์ธ๋ผ์ธ ํ‘œ๊ธฐ) โ€” ์ œํ•œ ํ˜ธ์ŠคํŠธ๋Š” ํ”„๋กœ๋ธŒํ•˜์ง€ ์•Š์Œ ์›๊ฒฉ ์‹คํ–‰ ยท ์ž์› ํ™•์ธ ์‹œ
mem-guard {status|check|install|uninstall} OOM(๋ฉ”๋ชจ๋ฆฌ๋ถ€์กฑ ๊ฐ•์ œ์ข…๋ฃŒ) ์˜ˆ๋ฐฉ. PreToolUse ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ(์ƒ์‹œ): background-spawn(... &/nohup/disown/setsid) ์ง์ „ ์‹œ์Šคํ…œ free RAM ์„ vm_stat ๋กœ ์ฝ์–ด warnPct(๊ธฐ๋ณธ 15%) ์ดํ•˜ warn ยท blockPct(๊ธฐ๋ณธ 0=off) ์ดํ•˜ spawn block โ€” ๋ณ‘๋ ฌ fan-out ๋ˆ„์ ์ด macOS jetsam ์„ ํŠธ๋ฆฌ๊ฑฐํ•˜๋Š” ๊ทผ๋ณธ์›์ธ ์ฐจ๋‹จ. launchd ์›Œ์น˜๋…(install ๋กœ opt-in): watchdogIntervalSec(45s)๋งˆ๋‹ค ๋ฉ”๋ชจ๋ฆฌ ํด๋ง โ†’ ๋‚ฎ์œผ๋ฉด macOS ์•Œ๋ฆผ(5๋ถ„ throttle). ์•Œ๋ฆผ ์ „์šฉ ยท ํ”„๋กœ์„ธ์Šค kill ์—†์Œ ยท ๋‹ค์ค‘ Claude ์„ธ์…˜ ๋ˆ„์ ์„ ๋ณด๋Š” ์œ ์ผํ•œ ์ธต ๋งฅ์ด ์ž๊พธ ์ฃฝ์„ ๋•Œ ยท OOM ์˜ˆ๋ฐฉ
pod / dojo [<slug>] GPU ํด๋ผ์šฐ๋“œ ๋Ÿฐ๋ถ + dojo ํ•™์Šต์žก ์Šค์บํด๋”. dojo ๊ธฐ๋ณธ ์Šคํƒ์€ config.dojo(์—”์ง„ ๋ฌดํ•˜๋“œ์ฝ”๋”ฉ)๊ฐ€ ์šด๋ฐ˜ โ€” ์„ค์ • ์‹œ hexa dojo <delegate> ์œ„์ž„. ๋‹ค์ƒค๋“œ ๋ฐฐ์น˜๋Š” hexa cloud fire-shards (์†์ˆ˜ launcher.sh ๋Š” CLOUD-HANDROLLED-FANOUT warn ์œผ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ) GPU ๋””์ŠคํŒจ์น˜ ยท ํ•™์Šต ์Šค์บํด๋“œ
imagine <prompt-file> <out.{png|mp4}> [-i img] AI ์ด๋ฏธ์ง€+์˜์ƒ ์ƒ์„ฑ โ€” ์ถœ๋ ฅ ํ™•์žฅ์ž๋กœ ๋ถ„๊ธฐ: ์ด๋ฏธ์ง€(.png)=fal openai/gpt-image-2(image2 ํ•€) ยท ์˜์ƒ(.mp4/.mov)=fal Seedance 2.0 ํ•€ โ€” -i ์—†์œผ๋ฉด .../text-to-video, -i <์ด๋ฏธ์ง€> ๋ฉด .../image-to-video(์ด๋ฏธ์ง€ ์• ๋‹ˆ๋ฉ”์ดํŠธ). ํ‚ค๋Š” secret get ๊ฒฝ์œ  ยท ํ”„๋กฌํ”„ํŠธ๋Š” FILE ๋กœ ยท -m ๋กœ override ํ‘œ์ง€ยทfigureยท์˜์ƒ ์ƒ์„ฑ ์‹œ
paper {new|build|cover|list} demiurge ํ•˜์šฐ์Šค ๋…ผ๋ฌธ ๋„๊ตฌ โ€” new ์Šค์บํด๋“œ(์ด๋ชจ์ง€ ์ œ๋ชฉ ยท g5 tier-badge ๋””์Šคํฌ ยท TikZ+pgfplots ยท fal.ai ํ‘œ์ง€ include) โ†’ imagine ํ‘œ์ง€ โ†’ build(xelatex+bibteร—ใฐใค3 ยท g51 โ‰ฅ10p ๊ฒŒ์ดํŠธ). ์† ์กฐ๋ฆฝ ๊ทœ์œจ์„ ๋„๊ตฌ๋กœ ๋ฐ•์ œ ๋…ผ๋ฌธ ์ž‘์„ฑยท์ปดํŒŒ์ผ ์‹œ
heartbeat (c22) live ์žฅ๊ธฐ-์ง„ํ–‰๊ฑด(podยท๋ฐฑ๊ทธ๋ผ์šด๋“œ ์—์ด์ „ํŠธ)์„ poll.maxSilenceSec(๊ธฐ๋ณธ 10๋ถ„) ๋„˜๊ฒŒ ์•ˆ ๋ณด๋ฉด post bash/ing inject ์—์„œ ๋ฐฉ์น˜ ๊ฒฝ๊ณ . c19(๊ณผ๋‹คํด๋ง ์ฐจ๋‹จ)์˜ ๋ฐ˜๋Œ€ โ€” ๋ฏธํด๋ง/idle-burn ๋ฐฉ์ง€ PostToolUse ยท SessionStart

์Šฌ๋ž˜์‹œ ๋ช…๋ น (ํ”Œ๋Ÿฌ๊ทธ์ธ ยท ๊ณต์šฉ์…‹)

commands/*.md โ€” ์ „์ฒด ์‚ฌ์šฉ์ž-๋Œ€๋ฉด ๋ช…๋ น์ด bare /cmd ์Šฌ๋ž˜์‹œ ๋ช…๋ น์œผ๋กœ ๋…ธ์ถœ๋œ๋‹ค(/paperยท/imagineยท /pr-cycleยท/sbsยท/fleetยท/fleet-labยท/ingยท/ciยท/kickยท/poll ...). ๊ฐ .md ๋Š” ํ”„๋ŸฐํŠธ๋งคํ„ฐ(description + Triggers ์ž์—ฐ์–ด๊ตฌ + argument-hint + allowed-tools: Bash)์™€ !harness $ARGUMENTS`` ๋ณธ๋ฌธ์˜ ์–‡์€ ์œ„์ž„์ž โ€” Claude Code ๊ฐ€ description/Triggers ๋กœ ์ธ์ง€ํ•œ๋‹ค(ํ•œ๊ตญ์–ดยท์˜์–ด ํŠธ๋ฆฌ๊ฑฐ ์–‘์ชฝ).

๋…ธ์ถœ ๊ฒฝ๋กœ = harness shadow (bare ยท user-scope): Claude Code ๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ ๋ช…๋ น์„ ๋ฌด์กฐ๊ฑด /plugin:cmd ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋กœ ๋„์šฐ๋ฏ€๋กœ, ๊ทธ๋Œ€๋กœ ๋‘๋ฉด harness shadow ์˜ bare /fleet ์™€ ํ”Œ๋Ÿฌ๊ทธ์ธ /harness:fleet ๊ฐ€ picker ์— 2์ค„๋กœ ์ค‘๋ณต๋œ๋‹ค. ๊ทธ๋ž˜์„œ .claude-plugin/plugin.json ์ด commands: [] (๊ธฐ๋ณธ commands/ ์Šค์บ”์„ ๋นˆ ๋ชฉ๋ก์œผ๋กœ ๋Œ€์ฒด)๋กœ ํ”Œ๋Ÿฌ๊ทธ์ธ ๋ช…๋ น ๋“ฑ๋ก์„ ๋„๊ณ , ์Šฌ๋ž˜์‹œ ๋…ธ์ถœ์€ harness shadow ๊ฐ€ commands/*.md ๋ฅผ ~/.claude/commands/ ์— bare /cmd ์œ„์ž„์ž๋กœ ๋ฏธ๋Ÿฌํ•˜๋Š” ๋‹จ์ผ ๊ฒฝ๋กœ๋งŒ ์“ด๋‹ค(๋งˆ์ปค ์ถ”์  ยท ์†์ˆ˜ ์ž‘์„ฑํ•œ ๋™๋ช… ํŒŒ์ผ์€ ๋ณด์กด ยท shadow remove ๋กœ ์ •๋ฆฌ) โ†’ picker ์— bare 1์ค„. SHADOW_MARKER ์ถ”์  ์ฃผ์„์€ frontmatter ๋‹ซ๋Š” --- ๋’ค์— ์‚ฝ์ž…ํ•œ๋‹ค โ€” Claude Code ๋Š” --- ๊ฐ€ 1ํ–‰์ผ ๋•Œ๋งŒ description: ์„ ์ฝ์œผ๋ฏ€๋กœ, ์•ž์— ๋ถ™์ด๋ฉด picker ๊ฐ€ ๋งˆ์ปค ์ฃผ์„์„ ์„ค๋ช…์œผ๋กœ ํ‘œ์‹œํ•œ๋‹ค.

์ž๊ธฐ์™„๊ฒฐ(self-contained) ํ”Œ๋Ÿฌ๊ทธ์ธ ยท ํ”„๋กœ์ ํŠธ ๋ฌด๊ด€: marketplace source: "." ๋ผ repo ๋ฃจํŠธ๊ฐ€ ๊ณง ํ”Œ๋Ÿฌ๊ทธ์ธ โ€” ํ›…๋ฟ ์•„๋‹ˆ๋ผ harness CLI ๋ณธ์ฒด(bin/ยทcli/ยทlib/ยทmodules/ยทconfig/ยทcommands/)๊นŒ์ง€ ํ•œ ๋ฉ์–ด๋ฆฌ๋กœ ์‹ค๋ฆฐ๋‹ค (commands/ ๋Š” shadow ๊ฐ€ ๋ฏธ๋Ÿฌํ•˜๋Š” SOURCE ๋กœ ์‹ค๋ฆด ๋ฟ, ํ”Œ๋Ÿฌ๊ทธ์ธ ๋ช…๋ น์œผ๋กœ ๋กœ๋“œ๋˜์ง„ ์•Š๋Š”๋‹ค). ํ›…์€ ${CLAUDE_PLUGIN_ROOT}/bin/harness(ํ”Œ๋Ÿฌ๊ทธ์ธ ์ž๊ธฐ ๋ฒˆ๋“ค)๋ฅผ ์‹คํ–‰ํ•˜๋ฏ€๋กœ, /plugin update + ๋ฆฌ๋กœ๋“œ ํ•œ ๋ฒˆ์— CLIยทhooks ๊ฐ€ ์ตœ์‹ ํ™”๋œ๋‹ค โ€” ํ”„๋กœ์ ํŠธ๋งˆ๋‹ค ๋ณต์‚ฌยท๊ฐฑ์‹ ๋„, ๋ณ„๋„ harness self-update ๋„ ๋ถˆํ•„์š”(์Šฌ๋ž˜์‹œ๋Š” ๊ฐฑ์‹  ํ›„ harness shadow ์žฌ์‹คํ–‰์œผ๋กœ ๋ฐ˜์˜). (์ „์—ญ harness on PATH ๋Š” ํด๋ฐฑ.) ์žฌ์ƒ์„ฑ๊ธฐ = _tools/gen_commands.py. hook-๋‚ด๋ถ€ ์ „์šฉ(pre/post/prompt)์€ ์Šฌ๋ž˜์‹œ๋กœ ๋…ธ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค.

ing add ์ž์œ ํ…์ŠคํŠธ์— ์…ธ ํŠน์ˆ˜๋ฌธ์ž(๊ด„ํ˜ธยท๋”ฐ์˜ดํ‘œยท$ยทโ†’)๊ฐ€ ์žˆ์œผ๋ฉด ์Šฌ๋ž˜์‹œ $ARGUMENTS ๋ฌด์ธ์šฉ ํ™•์žฅ์ด ๊นจ์ง„๋‹ค โ€” printf '%s' "<text>" \| harness ing add --stdin (STDIN ๊ฒฝ๋กœ)๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ๋“ฑ๋กํ•œ๋‹ค(--to <repo> ์™€๋„ ํ˜ธํ™˜).


๋น ๋ฅธ ์‹œ์ž‘

0. ๊ณต์šฉ(์ „์—ญ) ์„ค์น˜ โ€” harness install (ํ•œ ์ค„)

๋จธ์‹ ์— ํ•˜๋„ค์Šค๋ฅผ ๊ณต์šฉ ๋ช…๋ น์œผ๋กœ ๊น”๊ณ  ์ „์—ญ ํ›…๊นŒ์ง€ ํ•œ ๋ฐฉ์— ๋ฐฐ์„ ํ•œ๋‹ค(ํŠน์ • repo ๋‹จ๋… ์„ธํŒ… ์•„๋‹˜). ๋ถ€ํŠธ์ŠคํŠธ๋žฉ one-liner:

curl -fsSL https://raw.githubusercontent.com/dancinlab/harness/main/scripts/install.sh | bash

ํ•˜๋Š” ์ผ(๋ฉฑ๋“ฑ โ€” ์žฌ์‹คํ–‰ = ์ตœ์‹ ์œผ๋กœ ๊ฐฑ์‹ ):

โฌ‡ clone dancinlab/harness โ†’ ~/.harness/cli
๐Ÿ”— link harness ๋ž˜ํผ โ†’ ~/.local/bin/harness (PATH ์•ˆ๋‚ด)
๐Ÿช hooks harness install-hooks --global (๋ชจ๋“  Claude Code ์„ธ์…˜์— ๊ฐ€๋“œ/์ฃผ์ž…)

์ดํ›„ ๊ฐฑ์‹ ์€ harness self-update, ์ด๋ฏธ ํ•˜๋„ค์Šค๊ฐ€ ๊น”๋ ค ์žˆ์œผ๋ฉด harness install ๋กœ๋„ ๋™์ผ ๋™์ž‘. ํ›… ์—†์ด ๊น”๋ ค๋ฉด --no-hooks, ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋Š” --dry-run. ๊ทธ๋‹ค์Œ ํŠน์ • repo ์— ์ ์šฉํ•˜๋ ค๋ฉด ์•„๋ž˜ 1ยท2 ๋‹จ๊ณ„(๋˜๋Š” harness init).

1. (per-repo) ํ•˜๋„ค์Šค๋ฅผ repo ์— ๋‘”๋‹ค (submodule ๊ถŒ์žฅ)

cd your-repo
git submodule add https://github.com/dancinlab/harness .harness-engine
# ๋˜๋Š” ๊ทธ๋ƒฅ clone / vendor ํ•ด๋„ ๋จ

2. ์Šค์บํด๋”ฉ (ํ•œ ๋ฐฉ)

bash .harness-engine/bin/harness init --hooks

์ด ํ•œ ์ค„์ด ๋งŒ๋“ ๋‹ค (๊ธฐ์กด ํŒŒ์ผ์€ ๋ณด์กด, --force ๋งŒ ์˜ˆ์™ธ ยท --dry-run ์œผ๋กœ ๋ฏธ๋ฆฌ๋ณด๊ธฐ):

โœ“ harness.config.json ํ”„๋กœ์ ํŠธ๋ช… ์ž๋™๊ฐ์ง€
โœ“ .harness/enforcement.json ๋ฒˆ๋“ค ๊ธฐ๋ณธ ๊ทœ์น™ ๋ณต์‚ฌ (repo ๊ฐ€ ์ˆ˜์ •)
โœ“ .harness/keywords.json
โœ“ .harness/severity-map.json
โœ“ .gitignore ๋กœ๊ทธ ๋ฌด์‹œ ์ถ”๊ฐ€
โœ“ scripts/harness ์–‡์€ ๋ž˜ํผ
โœ“ .claude/settings.json hook ๋ฐฐ์„  (--hooks ์ผ ๋•Œ)

์ƒ์„ฑ ํ›„ harness.config.json ์˜ verify.checks ยท lockdown.files ๋งŒ repo ์— ๋งž๊ฒŒ ์ฑ„์šฐ๋ฉด ๋œ๋‹ค.

์ˆ˜๋™ ์„ค์ •๋„ ๊ฐ€๋Šฅ: .harness/*.json ์„ ๋‘์ง€ ์•Š์œผ๋ฉด ๋ฒˆ๋“ค ๊ธฐ๋ณธ ๊ทœ์น™(config/*.json)์ด ์ž๋™ ์ ์šฉ๋œ๋‹ค.

์ œ๊ฑฐ: harness uninstall (์ฃผ์ž…๋ฌผ๋งŒ ์ œ๊ฑฐ, ์‚ฌ์šฉ์ž ์ฝ˜ํ…์ธ  ๋ณด์กด ยท --dry-run ๋ฏธ๋ฆฌ๋ณด๊ธฐ). ์ƒ์„ธ docs/install.md.

3. ๋™์ž‘ ํ™•์ธ

bash .harness-engine/bin/harness audit
bash .harness-engine/bin/harness ci list

4. ์—์ด์ „ํŠธ hook ๋ฐฐ์„  (Claude Code ์˜ˆ์‹œ)

.claude/settings.json:

{
 "hooks": {
 "PreToolUse": [
 { "matcher": "Bash", "hooks": [{ "type": "command", "command": "CLAUDE_TOOL_INPUT=\"$CLAUDE_TOOL_INPUT\" bash .harness-engine/bin/harness pre bash" }] },
 { "matcher": "Write|Edit", "hooks": [{ "type": "command", "command": "CLAUDE_TOOL_INPUT=\"$CLAUDE_TOOL_INPUT\" bash .harness-engine/bin/harness pre write" }] }
 ],
 "PostToolUse": [
 { "matcher": "Write|Edit", "hooks": [{ "type": "command", "command": "bash .harness-engine/bin/harness post edit \"$CLAUDE_FILE_PATH\"" }] }
 ],
 "UserPromptSubmit": [
 { "hooks": [{ "type": "command", "command": "bash .harness-engine/bin/harness prompt \"$CLAUDE_USER_PROMPT\"" }] }
 ]
 }
}

ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ด๋ฆ„(CLAUDE_TOOL_INPUT ๋“ฑ)์€ ๋Ÿฐํƒ€์ž„ ๋ฒ„์ „์— ๋”ฐ๋ผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค. ํ•˜๋„ค์Šค๋Š” CLAUDE_TOOL_INPUT ์™€ CODEX_TOOL_INPUT ๋‘˜ ๋‹ค ์ฝ๋Š”๋‹ค. JSON ํ˜•์‹: {"command":"...","file_path":"...","content":"..."}.

๐Ÿ’ก harness install-hooks [--global|--repo] ๋Š” hook ๋ฐฐ์„ ๊ณผ ํ•จ๊ป˜ settings.json ์˜ env ์— CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 ๋„ ์„ธํŒ…ํ•œ๋‹ค โ€” ๋ฐฑ๊ทธ๋ผ์šด๋“œ subagent ์— SendMessage(agent-teams)๋ฅผ ๊ธฐ๋ณธ ํ™œ์„ฑํ™”. ์ด๋ฏธ ๊ทธ ํ‚ค๊ฐ€ ์žˆ์œผ๋ฉด ์‚ฌ์šฉ์ž ๊ฐ’์„ ๋ณด์กดํ•œ๋‹ค(๋ฎ์–ด์“ฐ์ง€ ์•Š์Œ). ๋„๋ ค๋ฉด ๊ทธ ํ‚ค๋ฅผ "0" ์œผ๋กœ ๋‘๋ฉด ๋œ๋‹ค.


๋™์ž‘ ํ๋ฆ„

์‚ฌ์šฉ์ž ํ”„๋กฌํ”„ํŠธ โ”€โ–ถ [prompt] ํ‚ค์›Œ๋“œ ํŠธ๋ฆฌ๊ฑฐ + ํžŒํŠธ ์ฃผ์ž…
์—์ด์ „ํŠธ Bash โ”€โ–ถ [pre bash] โ”€ ๋งค์นญ? โ”€โ–ถ block(stdout JSON) / warn(stderr) / ํ†ต๊ณผ(์นจ๋ฌต)
 โ”‚
 โ–ผ (์‹คํ–‰ ํ›„)
 [post bash <exit>] โ”€ 0โ‰ exit โ”€โ–ถ errors ํ ๋ผ์šฐํŒ…
์—์ด์ „ํŠธ Edit โ”€โ–ถ [pre write] โ”€ ๊ฒฝ๋กœ/๋‚ด์šฉ ๊ทœ์น™ โ”€โ–ถ block/warn
 [post edit <file>] โ”€ L0? โ”€โ–ถ ๊ฒฝ๊ณ 
์ปค๋ฐ‹ ์ „ โ”€โ–ถ [lint] + [verify]
์„ธ์…˜ ์ข…๋ฃŒ โ”€โ–ถ [ing]

๋ชจ๋“  ๋‹จ๊ณ„๋Š” .harness/logs/*.jsonl ์— ํ•œ ์ค„์”ฉ ์Œ“์ธ๋‹ค โ†’ audit ์ด ์ด๋ฅผ ์ฝ์–ด ๊ฑด๊ฐ•๋„๋ฅผ ์ ์ˆ˜ํ™”ํ•œ๋‹ค.


๋” ์ฝ๊ธฐ

  • docs/languages.md โ€” ์–ธ์–ด/ํ”Œ๋žซํผ ๋ฒ”์šฉ์„ฑ (PythonยทRustยทCยทGoยทSwiftยทhexa ํ”„๋ฆฌ์…‹ + Node ๋Ÿฐํƒ€์ž„ ์š”๊ตฌ)
  • ARCHITECTURE.json โ€” ํ•˜๋„ค์Šค ์•„ํ‚คํ…์ฒ˜ ํŠธ๋ฆฌ SSOT (์ปฌ๋Ÿผํ˜• ๋…ธ๋“œ: ์ด๋ฆ„ยท์—ญํ• ยท๊ตฌ๋ถ„ยท์ƒ์„ธ). ์‚ฌ๋žŒ์šฉ ๋ทฐ์–ด๋Š” ARCHITECTURE.html โ€” ๋กœ์ปฌ์€ python3 serve.py(์„œ๋ฒ„ + ๋ธŒ๋ผ์šฐ์ € ์ž๋™ ์˜คํ”ˆ), ์›๊ฒฉ์€ raw.githack.com / GitHub Pages
  • docs/install.md โ€” repo ํ†ตํ•ฉ ์ƒ์„ธ (submodule / vendor / ๋ฉ€ํ‹ฐ repo)
  • docs/extending.md โ€” ๊ทœ์น™ ์ถ”๊ฐ€, ๋„๋ฉ”์ธ ๋ชจ๋“ˆ ํ™•์žฅ ํŒจํ„ด

self-hosted

์ด repo ์ž์ฒด๊ฐ€ ํ•˜๋„ค์Šค๋ฅผ ์“ด๋‹ค(dogfooding) โ€” harness.config.json + .claude/settings.json self hooks + pre-commit bin/harness lint. ์ฝ”์–ด(.ts) ๋ณ€๊ฒฝ ์‹œ CHANGELOG ๋™์‹œ ๊ฐฑ์‹ ์ด ๊ฐ•์ œ๋˜๊ณ , ๋ฒˆ๋“ค enforcement(root-causeยทsecretยทforce-push)๊ฐ€ ์ž๊ธฐ ์ฝ”๋“œ์—๋„ ์ ์šฉ๋œ๋‹ค. ๋‹จ protectedBranches ๋ฏธ์„ค์ •์œผ๋กœ ์ž๊ธฐ ๊ฐœ๋ฐœ ํ๋ฆ„(main ์ง์ ‘ push)์€ ๋ง‰์ง€ ์•Š๋Š”๋‹ค.

๋งค ์‚ฌ์ดํด(harness pr-cycle)์˜ doc-gate ๋Š” ์˜๋ฏธ์žˆ๋Š” ๋ณ€๊ฒฝ์— ๋Œ€ํ•ด CHANGELOG.md(append) + (์กด์žฌ ์‹œ) ARCHITECTURE.mdยทREADME.md ํ˜„ํ–‰ํ™”๋ฅผ ์š”๊ตฌํ•œ๋‹ค โ€” ์…‹ ์ค‘ ๋ฏธ๊ฐฑ์‹ ์ด ์žˆ์œผ๋ฉด ๋จธ์ง€๋ฅผ ๊ฑฐ๋ถ€ํ•œ๋‹ค(--no-doc ๋Š” ์ง„์งœ ๋ฌธ์„œ ๋ถˆํ•„์š”ํ•  ๋•Œ๋งŒ). ์ด README ๋„ ๊ทธ ๋Œ€์ƒ์ด๋ฏ€๋กœ ๋งค ์‚ฌ์ดํด ์ตœ์‹  ์ƒํƒœ๋กœ ์œ ์ง€๋œ๋‹ค. (commons c12)

harness pr-cycle ์€ ๊ฒ€์ฆ๋œ ๋จธ์ง€ ์งํ›„ ๋กœ์ปฌ base(main) ๋ฅผ origin/base ๋กœ ff-sync ํ•œ๋‹ค(feature ๋ธŒ๋žœ์น˜์—์„œ git fetch origin <base>:<base> โ€” checkout ์ „ํ™˜ ์—†์ด ๋กœ์ปฌ main ๋’ค์ฒ˜์ง ๋ฐฉ์ง€, non-ff ๊ฑฐ๋ถ€=์•ˆ์ „). origin ๋งŒ ๊ฐฑ์‹ ํ•˜๊ณ  ๋กœ์ปฌ main ์„ ๋ฐฉ์น˜ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ, ๋‹ค์Œ ์ž‘์—… ๋ธŒ๋žœ์น˜๋Š” ํ•ญ์ƒ ์ตœ์‹  base ์—์„œ ๋ถ„๊ธฐ๋œ๋‹ค. (commons c12)

๊ฐ™์€ doc-gate ๊ฐ€ pre-commit harness lint ์—์„œ๋„ ๋ฐœํ™”ํ•œ๋‹ค โ€” pr-cycle ์„ ๊ฑฐ์น˜์ง€ ์•Š๋Š” ์ž‘์—…์ด๋ผ๋„, ์˜๋ฏธ์žˆ๋Š” ์ฝ”๋“œ ๋ณ€๊ฒฝ์ด staged ์ธ๋ฐ CHANGELOG / (์กด์žฌ ์‹œ) ARCHITECTUREยทREADME ๊ฐ€ ๊ฐ™์ด staged ์•ˆ ๋์œผ๋ฉด commit ์„ ์ฐจ๋‹จํ•œ๋‹ค(CHANGELOG-MISSINGยทARCHITECTURE-MISSINGยทREADME-MISSING, ๋ชจ๋‘ block). ์ฆ‰ "๋ชจ๋“  ์ž‘์—… ์ดํ›„" ๋ฌธ์„œ ํ˜„ํ–‰ํ™”๊ฐ€ ๊ฐ•์ œ๋œ๋‹ค. ์ง„์งœ ๋ฌธ์„œ ๋ถˆํ•„์š”ํ•œ ๋ณ€๊ฒฝ๋งŒ git commit --no-verify.

๋ผ์ด์„ ์Šค

MIT

About

๐Ÿ”ง Project-agnostic AI coding harness โ€” enforcement hooks ยท L0 lockdown ยท lint/verify gates ยท error & work ledgers, all config-driven. Drop into any repo.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

Contributors

AltStyle ใซใ‚ˆใฃใฆๅค‰ๆ›ใ•ใ‚ŒใŸใƒšใƒผใ‚ธ (->ใ‚ชใƒชใ‚ธใƒŠใƒซ) /