From 07365f71f977644a14c9cac244c988a56ff0e722 Mon Sep 17 00:00:00 2001 From: codeisme621 Date: Fri, 3 Jul 2026 18:34:00 -0500 Subject: [PATCH 01/14] Remove Signal add Reflection --- README.md | 19 ++-- docs/2-spec-driven-development.md | 35 ++++---- docs/3-the-agent-harness.md | 2 +- signal.png | Bin 494826 -> 0 bytes .../harness-init/assets/AGENTS.md.template | 2 +- .../references/subagent-prompt-template.md | 9 +- skills/sdd/implement-slice/SKILL.md | 84 ++++++++++-------- skills/sdd/spec-planning/SKILL.md | 72 +++++---------- .../sdd/spec-planning/references/signals.md | 1 - skills/sdd/spec-validate/SKILL.md | 6 +- subagents/slice-implementer.md | 9 +- 11 files changed, 106 insertions(+), 133 deletions(-) delete mode 100644 signal.png delete mode 100644 skills/sdd/spec-planning/references/signals.md diff --git a/README.md b/README.md index 0cdacab..2147d18 100644 --- a/README.md +++ b/README.md @@ -56,19 +56,20 @@ define the knowledge once, and it flows automatically through every phase: Impactful findings are applied in place. 3. **Implementation** ([`/implement-mainspec`](./skills/sdd/implement-mainspec/SKILL.md)) — slices implemented in dependency order, sequential or auto-parallelized across - git worktrees, each gated by **Signal** (the runtime feedback loop, below). + git worktrees. Each slice is verified by its unit tests, then a **Reflect** step + (below) feeds what the implementer learned back into the expert. **Composable, not hardcoded.** Multiple experts activate for one feature — a React expert and a DynamoDB expert both contribute on a full-stack change. Add or remove experts without touching any existing skill; organizations layer in private experts for internal libraries the same way. -![Signal](./signal.png) - -**Signal is half of what an expert is.** Where the expert curates context -*before* implementation, Signal validates behavior *during* it: run the tests, -hit the endpoint, check the build, iterate until it passes. Unit tests are the -default; experts can define richer ones. +**Reflection is the other half of what an expert is.** Where the expert curates +context *before* implementation, Reflection updates it *after*: once a slice's code +and unit tests are green, the implementer judges whether what it learned — a new +pattern, or a spec that contradicted the codebase — should change the project's +long-term memory, and writes it back to the expert. The bar is high; most slices +change nothing. → [Chapter 2 — Spec-Driven Development](./docs/2-spec-driven-development.md) @@ -102,7 +103,7 @@ state**. The complete state of every feature is observable from the files on dis and the branches in git. A small, deterministic dispatcher — **no LLM in the loop** — reads that state each tick and shells out to a fresh `claude -p` process per step, so no step inherits another's polluted window and crash recovery is free. -Four layers of verification (pre-commit, slice signals, `local-checks`, and a +Four layers of verification (pre-commit, slice unit tests, `local-checks`, and a runnable `run-prd-test.sh` definition of done) can't be talked past — and when a step genuinely can't make progress, the harness stops and hands you a **diagnosis-first** report rather than faking success. @@ -266,7 +267,7 @@ Run from your target project directory. Copies agent definitions (e.g. | **1 · SDD** | `/expert-sdd-creator` | Create a domain expert from your docs | | | `/spec-planning` | Idea → mainspec + temporal slices | | | `/spec-validate` | Multi-agent consensus + expert review | -| | `/implement-slice`, `/implement-mainspec` | Implement with Signal feedback, sequential or parallel | +| | `/implement-slice`, `/implement-mainspec` | Implement slices with unit tests + Reflect, sequential or parallel | | **2 · Harness** | `/harness-init` | Guided setup of the local harness | | | `/fix-local-checks` | Honest fixes for a failing pre-PR gate | | | `/address-feedback` | Triage and answer reviewer findings | diff --git a/docs/2-spec-driven-development.md b/docs/2-spec-driven-development.md index 6a0be42..4cbe505 100644 --- a/docs/2-spec-driven-development.md +++ b/docs/2-spec-driven-development.md @@ -42,7 +42,7 @@ it generates a complete, progressively-disclosed knowledge module: ``` expert-{name}/ -├── SKILL.md # high-level pointer (Expert Mode + Signal Mode) +├── SKILL.md # high-level pointer, read first ├── references/ # dense knowledge, read only when relevant │ ├── {topic}.md │ └── signal-workflow.md @@ -62,10 +62,12 @@ Two properties make Experts more than a docs folder: feature, each curating its slice of the context. Add or remove Experts without touching any existing skill; organizations layer in private Experts for internal libraries the same way. -- **Two modes — and Signal is half of what an Expert *is*.** Expert Mode curates - context *before* you write code. Signal Mode validates behavior *during* - implementation. The same module that knows your patterns also knows how to tell - whether the code honoring them actually works. +- **It curates before, and sharpens after.** An Expert curates context *before* + you write code; then the **Reflect** step at the end of each slice feeds new + lessons — a fresh pattern, a spec that fought the codebase — back into it, so the + Expert gets a little better every time the project builds. (An Expert can also + ship an optional runtime signal script, but a slice's unit tests are the default + proof it works.) ## Specs — planning lifted out of the window @@ -136,18 +138,17 @@ A single reviewer has blind spots; independent reviewers have *different* blind spots, and consensus scoring turns that into a confidence signal instead of a coin flip. -## Implementation — a feedback loop, not a single pass - -![Signal](../signal.png) - -[`/implement-slice`](../skills/sdd/implement-slice/SKILL.md) implements -one slice as a tight loop: implement the code, then run the slice's **Signal** to -check it behaves, iterating until the signal validates. Signal is the runtime -counterpart to the Expert's up-front curation — where the Expert shapes context -*before*, Signal feeds focused feedback *during*. Unit tests are the default -signal, but an Expert can define richer ones: hit an endpoint and check the -response, run browser automation and screenshot it, deploy to a lower -environment and read the logs. +## Implementation — write, verify, reflect + +[`/implement-slice`](../skills/sdd/implement-slice/SKILL.md) implements one slice +in three beats: write the code, verify it with unit tests, then **Reflect**. The +first two are the obvious ones. Reflect is the one that compounds: once the code +is green, the agent loads the Expert, compares what it just learned against what +the project already knows, and — only when there's a real lesson — writes it back +as a new or corrected reference. Where the Expert shapes context *before* +implementation, Reflect updates it *after*, so the curation and the learning are +two halves of the same module. The bar is deliberately high: most slices reflect +nothing. [`/implement-mainspec`](../skills/sdd/implement-mainspec/SKILL.md) orchestrates the whole feature and auto-detects how to run it: diff --git a/docs/3-the-agent-harness.md b/docs/3-the-agent-harness.md index d6cfd38..d69f829 100644 --- a/docs/3-the-agent-harness.md +++ b/docs/3-the-agent-harness.md @@ -108,7 +108,7 @@ Autonomy is only safe if "done" can't be faked. So the harness leans on checks that run **regardless of what the agent decides**, fastest to slowest: 1. **Pre-commit hooks** — linters, formatters, type checks on changed files. -2. **Slice signals** — each slice's Signal section, run during implementation. +2. **Slice unit tests** — each slice's tests, run during implementation. 3. **`local-checks.sh`** — the cheapest gate before a PR: lint, typecheck, the fast unit suite, skip-detection, and any custom project lints. It proves **correctness, not coverage** — it blocks on real defects and merely warns on diff --git a/signal.png b/signal.png deleted file mode 100644 index 7b4185aedfb814ba99865eba49069fa2e829ba33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 494826 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

XGVQWgi> z&;ym$!I9Ty_5|A8M~zWTntyt9(&0%Y13T!b)>jWJUGDbDzZOIc)3Nd#WruYackHwp8Xx7_2LK6YVORi#KzhHHNMXtPSz@Gt zEFovZixtb(UDHvU7z1b@D5Td@$^1%`&K!yv$swtRQ0?TS>%}VXVZ(FN23%lG_x%6> zKmbWZK~$CEnI8X#uKqu)*Z%x#|KUISUtjg3|K?Gj_{f+1PyfraKI3yf@#e><1ozx? z!EbDn2qjTW-R>Ni`JiUUdMO&aAy%4YElWHXq+u?)5Ubt};V9o84msMw7^{RLThXDj zX2O!7&!c>_YIccl4E|AoPGIQxzYQ+lbIwc;noCg!s>_ymT{VwV8R>3+L~Kh}u8YR&#a*$(VyUi&ERuz!F`pd6 z#R6MwGh13Ms;GCWcJ?^C_8gpNvc+~*6z8cBfdm|4Y=30qY=R*p1 z69*UbH!TyW(XP5)arjjUjE4ZbIW;F~YIhilv7YX6@zh#u>#kN9?vYXpRXlZKIF3Zp^?2FUXTFF_= zNepK6i5K)S%I1+xO>S-*WVm7t%*TXlDbI0o9c&$kQwXalHG#_y=Mar6*Qc}tXisI# zXH|$~q-rPa`a&H-C!K4+lcvB{r_gK-&1r$&o`C#NxBB6$2B^l<7cO1&Gx=}<=A;iy zpkc(ARQw?7KcDR%BO6{}dBZ5|xu?NZ0aH+ZrfdcGtC6au5g-oUdC|^$(e#+KMd944 z3r}*5Dvp%7wPSb7lw2~2kNfr@4Jqo|F|&;D1-9|1NjZ9Ur1MQ|Wj%r!D&cyy91NC# z%E4`0004bVhId@OxriLlW*e9iq!*QW$=@f{`$j~9td0q4HmS3#RcYva42z8P&FWz# z*=LZssp9~+p67|8R?!R|lcpouTji-(%Btd;u&kYlr$SUghEJHFZf`ssYE{HOz$y(t z__G$q@*p|84j~+6_tSmfc5w9iu;H92M1!^YQMLDvZovM7=wa0LcS#x{I>Y7A=rSUqDqf;ut zUTmKo>2v*JQ5^w;wU?ICj;&+dwt=X?cy19rn-`jB{enwzT&_lFT-*^wH3F2hvM=Vv z(N~5!{bZUSw8@(ACbj51Cwaw&(cgthp;Vo<7*)^Y?%K1W)UMNWoki-kIvIC!!4*1= z0O#U|PjsshFW*Qt^7e`kv*c~j$)yOvQ%9ZvS?xseK<}8IY*!eSdX^KmD#-BZ1r8`> zuMKk~j+FhO>HB^uScaM4|M*%KF?`HatjltCsDcNaNg@|6755$+V3--3M8!}H%%`m5jFsw zk-SxBTL>#k;#xIWo538xHNQg-f&#{o%P+0{DMIp?XHbd}$7s!h&kD<4MEdQw0#!9@ zh*`a3`VediK1c-#dt)^%MPF#9@P@5m$=y07`&EhU6vGHCQ(P7!s>DlQh*ZVtM_;jA zr-A7N`T`yE2nl~xWum(eIz`_3Xgabu41N?0EaWloa$%c%QDWUwx?l@I`S_XD`W3jId75oedc&cC}*7|M0uPf;fXq=tHFx|*5+H_i`Z6= zhx+AM?TjwK$VbN6R%97E5tUCk&btkDi<+)TaWQ`xq*sucbNcJ_C7Vs!V%<$xy19PDGu8j{9adyt?oeAFJR(r?W z-}Y_a@$LF6pHF@A6Tb0(c`n)_lVw_>tG7zdZ9BSa`+YuMmKsbmDr zD<5hrZhp~9DV{&i@UC~i^Ho3c!{7NG-zwza`@4VVtG@cHAMx-<_qER!yk zN<2cSZ6;A|`e}FOUSbFr*aV?Gj-j}*c4}KM8-tNSnfBX{);V|xiiM#l7yVW|5&?kJ zX~+CyEK7!ZU8Wsb2vt{hgXYZ-qo*S=8Q6<9K^=Mtr7y-p7Cyk?hrcG$Vo0-;<0h?U z0VG(-yky>lFJKdARL`^UCe~{D&7P@?QS+I=h&UV%h1G!+ljed8V1+Hlh$EsT% z*Q5fc95ad1_lb;qfy_Tv0n=dj8s!9WFT+9Xlk*^}Zp~>)qb8MF&)VPf6_|6;=9M03 za_K{Rz0e-FZ~-Y z<=WFX)4V-1IOE6R!P#42icpy{hM|zI5b{k3*_=?|dMB*_6Y9j8co0e`=xWj#X}BXO zEke>y2P0%wTYNq54*hClQ`h;{+TbiC97c~tgin3Kird%@SK~H9l;HMQ;rI$%ndLz^ z*GF+MEN+|WSV>`*ENXu?h8aFvEm~2lq(Q0oSC6h6JWF^Y1XL(nM_egq^JLYuyz)(1 zS&&eoj+ITiNQM~GmasN=YkQphXrKkzS?{WJNN$>NsNY;R;)x-Nhnb$o!ekhoIT~CO z1r{hxC|lK&Upp5^83$*reM4;qfZH~iw)$nZgZScb4u_PRi10x3wcq?w zRNgACCjhAV-@7P89BN@IfXLP3N~7qyFf=GgahH#0aEObiOh7H_ef=x9-ukoO@g3jx z@|XYMXMV<~|F{3+w?FrfJpX?8zuq5x5gqSv^ER!PpBK66%o0`;{1Jm}?%7cbp((@jr!(x*J_)1LYNy!N&K`jtQWvETdXlb-m* zhd%USqSPNsQZbuLw35{op@Xbl!mgUFth%s=DXDpqq$-xj6A{#U7pg@xo#sh|%9+mn zt^;D&PA_GJXv1zA^;9|>%BpI)3E*82U!_roqeBw5>2Nt@WO8!0edwI=4X6M<#V#!QI zYU&c#(_UOzdNtF%0Ieu*M>kjE?UM<-oHVddr98IKX>m9WA%?EXn%Ra4xJ>$LQxOKS zOu~YC+)eQ1OPvc6pV60XQsZkEVw#TNWIyh#Zb~Z*#)%Fo9LjocH+7WwySu9g7{@OS;aMxk;2HlxAinD08N4ZWwr) zltyHh1QuQ0k7I3u@@p61*_GCek@)c%Jx6U2A*>}DhQTl&9fwUqm(J^J10(GEy)H?$ z^o<0o!{q~gD+mMM-Px%HXXyDq}5kaU;L(T6!yRS%YW@FzUI%|^q@!RGe7#%H-cTha!E9&&z-q+;qp0s%!M_Y z7b2=3a^h58UK9)SHyMzS^GQNhtzB%O)W|h>PfHaWMZ?~0hii35E1uzDk^`TL-p-m@ z!$MbVCgI|ZST;gW`~#x1_yZ+AK`nNyvZ*I8$ z)GJ=`Q_p?g=UsR0wG~E{6%`N7E>uS9-Dx=20dB2JGbRG-E6DW2ePAT85L1(&rUn_$ ztoBXX=3;cESGMr4wCgUl>#&=7*+|WOsVWcu`ZU#yxr5k4dGZSNu-Up(FRO9xl?3a{ zH87kKBlwlXk*ey*a-~vkLR*r`gr#ox)G~`Ie3^DYuTrM`2#vaC%e(NTKAIECMz9|; z<>jw^VjS2ZgkV@TJtD7Knej=Xy*l_;#NaNd=ayMFNTXr!H+IQsaI0nRiO>lai+u|N zk<*FSICu^=Igx_!IJhH(HoZ_>RudjI-hgW;C25tmH9bn*0bA8$^y7w*2c3Z*Lg3JM z*f=@`O0obr^(h4v(8Z$Tp`p3#;@rovu{GDSM4#NbxZpES0-OE70fo=D-YoE}rb?p{ z6UxApUtoDh*yiX@BP5+*OIypp-^;AjX3p;nsx;^B+SZ?4?ljsRicfYcOXq=~T> z6r%xEPPy1?KxIF4KHXuRQ0Jtx0HyxHO zEwe(ZzJRz`a$#sL%@!XFxOl0LAPt{-#6nF>T6@1k7Ga>qM^ikVjxB>+MirY@u$XHq zov-Lxg5NbY?hp+0fMnJ-cQoAmO}EG6PN1!If0oQ?6da$Tz&Xu` zdfTy7ZG@p^JQs)BF6ZNYY&vgEPsE+KzNM(LnxpLbymSZkyVv2By&z+k=A~PfeoUB& zHBtMH`JrMSH||ZY<5%Ls+WS{JY4NRe8u_|CyBFzQ=NLCS<^V{KN`nZkE% zIa-S*k1vw4pH^Vy7YTf;)$jZ2l6u$gyi5PN@3(x*H{W>b)c^dq|KXQ><%@5;>A`&B z|FnL4RlOdVPU}zpD~jIdh8D&S+QE2JJ4@Huk&|<(7ulLri!|q@7RiAQ)1n`C1+hF7 z#jy-BEuJ<=H5_A8pT?2~8CoVC~0FG6C&ZGo1UNHiHxdBcZpRL%B@v@|*yeZ++)g4~P288*9vgaY;+PYj zYk<+;gv;&PQaTR2!l~DnTJZ4Nt_aarN;bp_Z4*ZxQwia*AdX>|f(dhfPXi^Mxr5s@ z10j_#z7{HCpjYn;YdXhC)G}u+!xqh?!;ox+CX!kfGBAT7iKGuqJuth)HyU~!ovvgt z5W)HQzEC`NCeu1!T}Fr3U5#Wm8Hk&pgvD(%L=$7SHzvF0zT-#(UL+=Wc(9ez0*dHT zLM0?|Qd(>y5EGhBUZzc;M_VTav5GYgQ2zvADtt)15W?$yM|H!R7wJpYViG+M4@{ue zx9^G)5($I8HL2SJGMDbqH_uQM%QBZpGr1)g!)j#=(;UfwsSLin%#y@}Fq)wZ>b`#k*7I`8v(Nj`ywNylN6avc3A0r?^?C<};2VVNpm;RIQ z{_bZz>zRMw*xJ_&n2PlM>8H(#1xQ>>vScL`Cc5 zGTZe7iCeYFC(!j`Vd}WQBc3p zM=)ns)eWVzscA*fTuq@Xx&|eTqZO60&76NJ*Jkf!Gw?~c6=m6UmO`Dm`5dI|6E+yA zOsX_g5hiwt8KsVpbIti4tJo3jr;|_?YR6C@Y$NmNvw9`R19zP&&aRq#NjuI_S+CA} za@2xyi)|l|GIcV{*&``@Wg)lXSuX{3kIMf2_N=Oe~uls^TQ*$JO>S>HBnF3RT`0TcXsOAL7A%6tO>QA zsJS!wVAkB)jYDZh49}JDsN`_zAShBFPLHb=4EJK<5LBbSJZ-c=m5;q7he*Nmg)=Z` z6?G>32wuHY%B=mH zY~$>j3`9)MMPiS`Vb-7?hC9IS91Mpe0xn)Yw)XE^VvKc6mhg?Ut4n6)sV3Ps5R1BuoxY>3$W-8|XKxKCKzgjspprGvqq z2yqZU< zz0@OksafojKN}kus}<4{&Nfe`lYLlv z#6?-yO4Lz1WG;)!jf9po6T3L@QWIe0gQj_GOqUk`LaDV=l~T^j8;lhyYv>h~*UBro zr*`3FMCJ2ck0K*2jB9J(Raf!}rqJ5h1>QN!Mk@NsI(KGIV+mI)%!!}8OKw+Bi!evD zcfMA(!?)k02C$YoX%6}!G}CT$ zZn$p`dfbZgNJ=Yh%b^gD+|-iX$ZO~pwqCMri$3$ip2doIEEz;aUsH`refZ1E*n$O- zNf8V#V&LfV&H!s9u+;{~mS&leZlg2$Fdzcf*lz2J6o?gcfBL{Qk^g?Y!St$ zHq=dz(y}bWh|+C1)dL3D+|>p^tIMk|V|7qhW+u%2M%3BJEGWCCfWBqvi()? zzVVH3`g{N2@4e!OfB4J3;w!%4Fa4D#J@r#BUA%JPBLA(`bW(6X{V=szLoL15;Fx{` znq7|9E@`s&N^&z`?fb=#c`e~cbzs@F_F?Sr4d7tX9tQ?14y;n-i;>lrpR!+OD1lwh zvv65JUpaMFe^`lip1ypMdzW5Xs;ZB@<&$oH+%2!W^{4*rzx($e{P0Jg`#GO^!wokG z#HMhM>qlMu^hKbMR1kty9t4WKtEPhK^+0Zu+{yx5E*(Net^Sxaj27S+sAcKW<^1Ki z4oJL}#V)Tw0&?ZdsagHY>ZMmQtHY8+Sv5GF5o79CsU3Y9We91`=8D@a*qgYuwmmtI z%q3V>CuTK@P@c=9XJKM-KNmNpjsXo7($C(^SX;VyZywMLim&!%zXc;5!Ctk0b zpcDx09(4KmQU;)TQq)AEiPUp`MHbztg4$r^(IIC7Sb7XVuw(EKQmg5}Mk&{t&*C!)$>UdeWn zrVAj+v29844(#x93=P`*-s}@kM>x?rzz~yZ!n8KGLl;d9)+&o*i745)4=RB2pReA$ z9(?1kz6o0u-}D<`IjI=Rf_}WSMs+7d zQ91}}gfVH{ek?zL&RgSgAG8gIq%MR7EOD-F0XunI4Is`*i-6W>0vu~gv}umA$nl@o zD4?wm<|uuDl(D7*Vyio=qL0hy@ea;cO33&jpLtlE*PiL5)_mIpt1~?G6*OU6TeGpK zX^oV`s`TwtqxK_NxsNhl%~IL+lzg{~D+c?@C_IoXlSOksLzj>J01KCK<>ewn%O}vi z5Mvrr7mO}VeRN3gKVQE5<~RS!7yYs4z4mplfAQD-`LBP;UwQOnZ_(%cFJ9DTrXLQ_ z=}GC8i(Gm7&c)}z-WX-1SOR$=NKQ$}9PvspR*-C&x6RnKn+!vn)n!_%fUwoe*jBKE zXb4g+ZmW985qABEG+8^4MuX|%MQEC4gyUa+0K*POJad-M0_nxoHP>D9=*K+n4}8{h z-}^i7{P9=*oAJ(QG+q6V%C6vOOfO$t!1TDxC_p%qopI#JpIghev;sqbz*2=~#Sfaiq=c zf@qvZdF#vT)iLzV%~RY4Gn(Q;cVv@BBnikppNh3;M5!fM7%LrS*Vz8Gs1Hqvq?2p3um67YX~;H)~{UxHA@2Y491c*hI7)4 z%3{dfqEbU)*PW0l=t*qooYt-qmXHlRc$9En>FB|EHpugIKf3gZt`v1k)eS(`PPV4~ zn!s}=`pQ;~q^Kn?0J^4?JVV{52U*-xBR??4vg>6}TENXp;8vM82u_B5L$CyHkrI^5 zsI@iYqHVCphHod~!M50)S{S#6r0UcHS6@dMsdr_e@?JS)bw#nNBukqu-08!LGV3$5 zl~T~~_2N^qC~Uwea~24JvonBTW`dYU>M=1MZM9^pNw&_=qG$-ti+|KZ(L#@yS9w3P zy8ywkf-O4kLpxTt>f@f`nD4N|n6(wy5qF^mAmn3e*bci7QDzO=ow=MkEzaMNUH}uz z*4kxcXu($%<%lnvkcowT`2BJQ>jXwM=aD*}y}p+~&||h%R(gT7vK+=#LdRhp4IW~v zavzjB*H{$<*cMtEVhiI7$)6OkUp@SAZ_`~%ALP-e)A?Zfbt#6Wu)yqHdyC3|Nr+msIAO5h5e3ZXq z@obM`D4@EWfF+iL3@{N#X4}=H)&pRjCD{7xg}OMkyNT5Ej6^WQII(5tep{l4fL2Y* zfvMM*ch?1K>pBLxYL3Za!ZH>T#u!!-YLt zoleZHU^eBA|nswEbSDxt#4nIyfz;!=s}j_P4cNFJpSb7$;*Sx=xIJ zR0QD*)CvW^c=ptu%?@CEfoKW=(tNwhx*%J?8LA9a52`$_B z0)9dpbkkluJ4>e2hp&!hVH`X#28`AFQQBZ^wDue%Huwf$t3m0sBdUt`CG~cVY~y4f zY?l3fKMICiXmOU{+lU zeRZRiJFf{usMbi4>g9@c*jjDO(nVhhoB-k-#6bX=qnJA4P?1OgONh3X->|@$H)G4C z)@05+AqTq+(ca$Q%Gd63a8h729jr|4$3eHS>1F_o0f^qBM^#T+6h0q8@RT2|lJ-9+ z+sD!4x<(>JIqBQjQPLH&k;7+j<+Yg07&hsZOfnmq1`nD_F#0+*OeUaAO_gc&3#vp7 zY9nfdLT`r^DT}8RNQXW58!D`(zV1fjBDX}o4@&U>#hIcul}qQuGGfrFBU-IO}=#5KTg0u$6uV#3P5Ogbqts(=H|YDZf!}e zecQqs_PT`WzL8_xxiB5Jqg9=VL`sd~qm`ysnhK|8vPDEU87h{yCg4Cvw(G->0{MSU zK6Co=rAzvqiqn3p|E&I=>iIMOFJbQjeCcvk_uZMf4}lOEJ&}wkz{I8`gm?%LA_jvD zrh*Az0vJ#zg8{`c2_Oe2K-uC^fNfq?A&8fN5Z;h7!2#kFBuExuFp}+*Z7_tF3W6;R z7(y(>y)*Y_{nlE$yU&@C==n~6yZ2su?cKZk`_AKk{{Q*qU;3p_`oQPE?vGyo37`0) zFaF{$ddIha2N7vi^}jL5iz4IAKf;idmS_F?sF~#WwR!7VAYY#_q^|ou8O3WKFOO0f(#+5! z-Y=(uvM0Ipvw#H3o5JbzXn6xtjy~C zu0a&$T6Zy?YrRaDHU&uO2$UU0)D;(@+0Dc{+&oS*Ni6WTj+7)ro)^20i1|(DFTe_Y zq8sZj=PK^f2QZh_5+jmN8PGxGi*q-cy# zN7J6q&!VNZ%gu)$e&nZr=G8Cy#E<@$|KjI9^}qP9Kkc(V@2#HnWWDCs&jj@9^7f

Dy|DM`bH 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�g=I)weCetu8?H(3OF?-zaYpWok++vCYb7 zZALW#OEo*>f=KOp5dos{SjVY_47N3=&KlZ#$mJ1J^|uh~JbVL~Lor;~O!2DM{F-)6 zDgv~~?oh<=bXzA3b3{BJ^0K}p*F8Sfj+?_v_{%hDRMDdWHfmkQ&$wbPDbr>3tEH|B zpmmN0M4kieZFzJcr?Fx$w@=dzYKA??U6u8h-3z6fM)w@uUKP;pa@{?Z1xI2@PgN)h z>_}bsGe&8d7HKpzQ7aE2!=@d*6Jf~Hv};_=@u{L=B9m9XacbbM!g8OrSVhoRoRDWS zhlk{+m<&D$Ljop|4ztrOof)n7CkYafSfKgta;-on14FKdW{e2)oxRmXYsgxg=i#_O zcWF*QZfWB=2^8c0#6W^1*1GMPs%zy5(^5C-&e(i1c+3LuP`dv$ZvxA3^C?B*<{ro0 z7w?Z>{P?|}{OBh?=G)(SdGou?-~Q&eNh@D;leG6vVnst11c1rZLV~_@+}$-0!h$ZR z`Q~2i2_APC()O1b0wm$(+Vf1LZh1`usPAL1>!>R8>D#3pDMKq%^*z|}=MnqUs>$fMcyJo@oE4skWf!xq6TAAo_Y zOs>N?D<@BMDTN*<%IOA1&`+y+6tins_&045>VgsOUZg8@pm+=%Y0e4SLee8#5KLDS zRHI0f$o!5Uio@7FN=j}?t?E#eTK8Ui*jEp6o`CMaE1d~D11QCU=`+2I#(z*9-YWv+ z0S z{ontu{_%hR-~HBa{U(3a{{?pnK5WlV_veNPhbMq{J^94|uaubb)<2JYJ0O?LlUM)B z@BGe}zw)K$ujCJg_T}6+j>III0|E)Caics=>3D2vCTfN0_ylu)htIWhDWbFRVRbQ7 zRIPQkH;`IV!!#H94qvVX+{gICFp(moa0?Mw(sXkLIyC;Au?^2*sXFx*fTw~}KZ)dO<@Q{%0?0kYiFE-8xP;~FG`{dPexJ+so| zC~(igQJly}xI%Y_fu>Cy7xiE#MiDRd`xR|{bsr9ZQ^QTO?$-_n!=sp9XQ_tDTHGep zoKQ|aahdzy@OMZ*VP%kfqgHcf6~_B`9kXB1uXXoK>jq#lGB`x<9HaNB;OM`(r(heH zscrz2T;Pz%slbJ+dKXM1H}tlE4tRB{)K+s+x&SvR>pF{nl*hM1`itT*-QN) zJbCrWYx%z|^DVkBfBDPf+f_|gO)R79jTKFIgTsk5v${4;qBNHWH&62^wRpeS*o96M zmkU#LLWd_Bq!UYZZGiJk>%1ANsQwc?54Zhp0!z!)1=j>R>>Jg^o?tODHJ=OEZK0e# z1g|+`BbeIN!Lx0|OM`TsvXi7auG6IC^x(;?`4X9*tYFj~ z)@UZ4(m;1WC;o1{%M1L(7%xw{-deq;<2#y25bZV2ip=?nRv6~AEJLN%1#T~*>Z8d5 z>QWD!CJG8rMP_j4E{%Ft3?CnOv@OMjR$o|+I>vq$9Lb5q4@`LIn;p=*lY7uChJHn0 zzi3iX4zi2bc*yxXp23jCi&ww(&2Rmq|K=b5-rxMaH{bf~2k(EFpY>@n`4XUM^3?^m zA^tWHzaS8Q{wnAzAAI!e?Js`u>tFvS33j!OYbi~@18UNlXPhq)NEg64Q7IRTQNDDDFcx(<~?BjB%IXyx$pP;6O%DJF<4REIlX5GnT zHb;~$D`}N_m#CKX3KQ(gMrlJ13neJd{3Z0=^fDqH7Gurr7+drwdd+0)4#CzE5FL3;Bu21k%A zHwQKl8TDaB+FJ}>=Tm=D*_$CDBxe$QluX?>|LWS3xTK=bm|T2c&Lv$FIvmPzV_PdufOs3+dr3|e1(;;(nc$% zc{OY5$Ya&BFw~bbOtisO*q%_6N~Bxc9HJWW(nLBr;xY$mfj5?HEN*6zG0C|iSyfV+ z)PP7nV+Id|IxU<2Y@*IYQ9ofT%hXLn^XYy(I1Rb`y~_Xb+w|kl_e{C$pXD0?AHVopfAc^4`7eL*gO5MR-%yCb zx6AXMkwmDm)U6Amo%~&n%;$?jZc{F9{Iw{wZ zz7JW3ilKxEp1i{ojq)nU$JE*0#Jj>aVzdQhTA!p{5Fr*c(pfv*PRB{;(v9j?!Gg*} z@3YhLZ?4*0Hmr$N!=!~O&o*~zMMmmOiz7v{#VD%0naH%SYW&1RA5ryDhLlRR?(9vk z@ueE|S1b_;anp?o*Shp?Lw*$blSK~#_g4vtmVmU^zJj*-zm(-pxd2X~F zvEg^k?~I54QVR4`dmJ=G=WOjfB$3A_L?qHOg2VHgqk1zT?olwxn0KN_K870NuZ+1 zS#dVQAY+ZeOzCL}V&Eo2Ld}W66&k?xo+Q<(tN--nyzyQ4qz00f{rmslPK?RgXwY4y zMKV3E_y`-06VN(Gm=y^;dEq0)z;_KWlpg2D+{I(0ff6|cDh+|5(24(G8n5aee5=|% zzFSMk0Ovd-D8@!BO1R3N6vc`fK$61f(80?ay~&odlEGTMRM6dMB-!7oglhx=Oo%X*g@ zLQS1yam!LlDe3nNFphpztUu96$IZ@IM}f>p56EP7XsaxINb<2k%p!Vl^oQcMwD}{R z`HN@yqyFFc+E@SKKluB9_wW3jFMRRs{Aqu0ZHdKNyqen}hl4R3`FsEI`qGzv{x^U9 zHzGgbCm5mT=>zBlRxwotL>VznI;%%PQi;`jbRb|rYfG0sC%}1xAEWk;(>H~^GO8Tp z=?5Jsg)s4j@?hGi{6q7LX=DFlGMHhnOS7E&ZHB%tB+BA<(EPaRo_y5+KPf!a! z!HJazJ8?^?fojsSokT+Od0@$I9}J?3(p~OF*faD%JygMMGHPC$oatd0zk8OWI>ltp zU13^t;d*~8r?mn)j%R(Uy*Pq#Khs62es&b!RK+H^fLJscR@@JTuE{B;7~PU;O2}?|%5vN4du(f#=Vkz5V&m z=M^a*h6SBpNxK4&qi;Z#loZm)DOhtbBQYfa06+jqL_t(HJ10G%xrU7uW8A@Ia3x77 zdxrzWphP&wNYegTEiu}vj*K9}aV9O&<SuA=}UgJjVJRtY*0&r4Zc zhfje`h?$%xIRN+OUNrB`JhMLTIOWBSL8`9NczC9c+XXin^c7NonavMHPDAD{4);hasSr}(29)``eOyEMKNk?kxsaB`6o9yLFE_VKgV zUddlh1Cxi$nQ&qVKFLIFx)z{Vg(Z+ic8f1obmteaiiSdMzLGiB3^PNXv>ngP?ZIJ< zl}96t+#X0RA_duqOlY#EKWDi*OpS;TFH_-#tBnyZf0!>(F>~z56jOVH zXA*<`35Tn&hIauduAWr_05cFXHFsmYyb4p*r`i%M`uOGa&HP9yR%+EW3VEKK+zn>2i-L~jZs z?tq)AoB8Z&Qj^^1knk0)SFC|dJv&Criu2pP1b_M(|KE9ju;ry`g8yJQX#+i`|-19AN|^|{_0=sQ^9hFu zdyqEVsq7>`z5rlApTFX)wb`3WO780X%mBJR?g7-3#+bK-C|b`JwcdAh`PB9T_$9E>iE zhXx)B&I1B^#><{bTMV>J^5n*m!6{~B#>BkGsp{&@fN2`JxJl&+)wwHTg|1J7%)I5| zo)!;+iECx%Fm76!6%Ya9FAzCsit2$m+E1)NwkE6DfVj0S8E{zUj=JV5z57H}Fg7K+ zs$7T8sz|>U;Au<`EWwfvi_Mn+*k&b3Z&HYo&%SD;SA;4p)4Iuo5zo-L43(>}k6n-Y zbrA&VUh)B610H?y6FEVWj67zNh@AzN7Y%Y~wn&{SI321CCpW0Kc{-RhpXnXMAI0UQ zWLRs@-ex^tedYb1zW0N_{L8$a@g42g@}B?2XFmIxd^DDgjmLcBGr&yxXhIuGR~2cqEdb)1lB*>+WOyH{bx`G=7v!Mn_Qt za}j4@@pOrXqANEOoy2cfXKHv!%2bWZW^B9BCY`2Q%w|ED)kG}hZXCdUc^YWQb#E%& z6s(KxxSJJrEHb7K!K{IV>S5a)z)c(IZFhCKnIpR3Q^Jko5*uOS;5*_j_;OB?yqAQI zzO)E}T}t#kHbC73qaL$iRDvF12q~-7mFPzYqBHpONW=L|kh4~`U~Rhv@D++I^r=9f z7EOgaJQvbYB3S9sL=pKuO>Dxa(1*IQ~uf}Zwm4X*DnL|?mpiN zc;)%qUwHfP{+IvxKlpop@2g+^%5(lh6n^+8e;GNSjN~ol8*jYzYrpnupZ)Ax$>+%{ zug^-QJSrrG-K~f;R6Omw&Q9&(!pqrs7S{wRmp5p2jkoV#*0V7tQb~g+w!?v`Lytf^ zbe(2iQ~Ft;NVllPpB`cE>xYV!<-~L7S_v9(Go4Vl62r|Cd>N1?M|Ncm6~k2x=Yk1Q zs$q7+%VKb(mZ8HElGDgDX80KoB22Qn6sEE+DdqB2WZLrZFvaHSRAX^9qo7gG_DHm3 z-*$wencgdQI;$}rP|Z?pgjgmBC7EU%tu9xEKPzWEm4yy5gQojZ5Gd4nBo*EwBIrgy z;l|iW7z$q_9;e}h(|+H?x$I+L*XGoX4MQ2zUwexB{`InRI#TLama1fFn$Fv?pI7TD zF>iq-(O%E{#*F7uE>TB$bAe>WWzvm+SF&`E@YT-93g3#&Y~dHvfhur3jFlO|4n84Q zKOWjPA>KL%PFgpYBOYNA2bY#12Vgl=flQ=)#8Ug64$W@Z{YbG$TUkVAAYHq;tHl*& zp7!0Z0lQ4BR30MIb?Jl;;kq)$dhKyRdT#{Ry+Hc^hqX5i_VudHJMVlo3k@KIgv1~a zU^AFWfG~rN0}0p!DBP7esdOso>ZFItm##{>QswIEuI{e(r%qQTl}@VrgJW!GFmX2+ zh;1;QVr&Cu6!R=02_zvjUFnYf{GMm6z4!Y+=Sp^W?|aU>_g?E+&l>iA-}gVA|Bc(C zXVTe4G1N8iJw^Npsf8mn4e;(;l4@stmj!QX!)6`YY4qcmdJ2w3bwf#!kasm8$X%}s zb>P554?XnABaiAXr#Hd{zTl#Z)%2&p)IVEEN0H2p<-&!TEv;NEF~ZLJfNLpvHbl$O zLk@%>!?1_nPX}`SDj4*&#Rvcn(`X2VyC^&qn_u_p&18f$nJ)q4L@KI;51|E>pUh%V z1LrCkFC5}pzLIj5Sy+Bz;yw~+)dX&>A)Y&sa`dm!xq7l&2Z8;wHK zyUg%<=;5vzD)+XLxYF+6ph)qO?=-9;m#I8Blr^5H_DZHVk7}{DxFpEY%&qhW>dIxC z?yz+orL?6Euv9ZoFWM>#sF6ZU(6X7LZ&cZ@(~8rg0(0H&28Jzs)z@SGPH%1!=V&%2QXP>0YPl2@-8F7R%_@Yo! z7DDP>B`xJ|2Qji%2c)fOnGm_^U@0Nq>@kldaxK%9Nn4rA%R#-;umAe+;Nc_sr0Bu3 zM~@x5`MJ-1$2;EsvX{Q($g!jP-%<2B*U`gA^ale^e)84Nd+yD8*mL&WX>%(sv+4g3 zOKEsp+*c$#JFb$Gqt@QFRT$nyx|m2x6V~qojXXOgUxl;fd=#5ivSc2w5mCze38{IJ z;3YppA!8*EgMX0c9bZOZ^;>O@L=@*j$fthL!Jx}-r3=8E6=$YJRUImDg)C|2sYn3C z;U67vjrSQ%`ChEimOho$B!N|(ZBpZn-QEfDVV*ddRDywKRi|0GMSulnc2)@cR80pg zw4hu>@0!AHeMT5NGdC&@#;gb{xy(>%lx1QvX_(QLbuK|UDTXGprMUtV6$MeAg%AKt zX0SFm5Ojv@Q~kC>&-30idR`X9uza+y(HC@fJYL754cfR#rJci_$z-Xk2ZHq#Zr3r) zv!o;5HgEp)K5DbL*W=#aPN71cA(wY zrZw5Zxbj1$-*8U58l|$Uvaz8{sD6ytwoNzu)y04aEu#Q+RT&ukXT#!a@#i71$ZWcL zk{Hb*XR5r*gNtJ~4?g(N$;TekNB`wWS8+Z1zv7B3pW0JqN5Fb2mvu->?3(utYf@q#?&JYV^n@LAM68Eu<#ie41h5jOv5Z(12E*ns%wX7 zqHc_f;%ua;e5b2IxlWdL$X%KOWQ`Np3{PM)FNGh3?Vo;HSc(r5mb@1RnhBjFNjogt z*H)-8CM$M#7FYtUaq?F&Oq<+nrff8$fYzvspL;_{^2Xun}*ZtG76g zTA#8yCTyL*b@R~NlhYE|DtzYc2P)h8?2B(5*ZgL5iN$kl;IJ(W88k7fpzWMP>SsXQ z6h(*v3w12bPJ)AHR8NvFMC^QY1PNnU88+8g*EIk<&`{c}^C7=pgH*qMwO@~g4iDq>UjEXTU2x$AvO08-4-P4L@z@o)DQZ8YM>FD) z8ftuU9508APsD+(4*@9xfc3aX$>zDXWG2ajBO~M$zdKE+7TTuOn1~HstZUlf(1VWu zA;&Ju*mi*ATAuvM3?_(jCzf3ZBJvR>gQdm70uA-UvRWuvGU(Z`f?7Y5zAaMU#tl0S zh@3ffFV-ZsrZ)^m02tcJoTYCb%ZxB}2T?XydZkQOZl(t!LKCvZNwIb}EkY*w6nUgF zsOK!{A5HyJ8vt$7F&Gnu%SB)z&MJ&E52MAZ$<)V{1+^U1qOhgZOrvgI0U+#~Eh#e| zWLqjaVJbW%0y~JdY0mC}7}cKi2pd6fLvRZgR8v_&JY{Nk7FyC`^A}_jJ8Kz^Y1BCP zwLyl=j;Hq_AA>MDAcdtWEZ})!%U@ZJhB|W)$xd?<8dSAud&xY^j_M3;JM3*Y z4$|RZ=V5?YigMTvi@5Z<)+-*pu8P%g9V-bOFits24~^rl~>ee3*DG!FL|4m z160d!EwVH+Z)G{}X;Wgb8rfma9oZIIVHp!;aqconEFVA&i`vH_b1<5z7VY1CR?D#3 zHCuH+7_D|p<5AnGFQxb0|AT}2{(pbVg$OUX=;8~GA3t?kFM8=-MQC2VIwyA-<262V zRNl1{M8=ImmK6hnE*%=eFLrD)52KG+fTE>F81!oUrGEG*)VfFVkjA%&|$GF8p7(69L>U?4qcdDsz|8Z$L(YrIH? zDl(4cM<)I(SDgq_v;&Vu`Nj_0kQdr3;q6fT4RSvSsY?Oqss=6Uz7cUfj4>E>#V;CB z#LN?wLl=(GzcBZ#p)&xpG2wE0Cwf#2)%rzlgJb~ zsrjl1kBmHU?AWmv{>YF1<+r@$InRBLUMSJ0|MmHwkmxA-+A}@&QQWyyqN?9$6>8VXjPFE#E$~fYfWOUf6YXJ(7?}w=K1`(u&L-pRZpeqZOzt z?D)(CtO{gH+OCENqrBp)gGzp&G}t`}tRrmwh@@K$T~RAlF8UExfPxXVCpO7Ya}S!3 z{lFN89)w`T(=3y!0O?G}LFQuO7=Mzr7i%L1WD^zDeLy9~CR&-KAesi3W1K=*b5;ev zEITc?%l2Hcj2tX4rQ;nu&@&W}tOq+79Yq3WKArmC4G6Iu|7 zQIM2eWQhW*SIngaKydJ^4H1u2OrSsMAx1F9<%zW-Po8h6H6hNrHWkwLbugpHA;TJPDFW^_L@0G(O_tq5ta30{F(F~4-+c1M$=1S4 zoNJv;L~MJ5<09ZHy=%`ZR3nU?W*tThaO+srhqxjS%26e5SQ3(KD~M(mxa({?%l)Pz ztaf1b;6ZyNMe5dju=2KgL=Gdl+h-W&QM3&tRwI|vPM~#6M<5kO=56Duz%-WMhV5hF z^N`q-AQfp9w6Nsff;ED6Rww{AL5}a#NLmB2Mp&fQV?eB;(&ee(2U7ahOw z@Zlq;&z!pI>MJh0>@uE5+t?PdpOumm8LG(%C?{=!v+0q2I6Fz$v7}U{GO3eRyOaE# zgk8qmK1m{j_=Bg|SDzLc7ypI9m0?n0N2gypj`@RE#?j^CRLfftaXOjAe>14@NB}zw z{aehrJRt1oq7VZ@m=I_Tefkh!B0*`H4LKU*OY=009*R{n#WrwuQJ$m=Ho_#>0oqZ; z6`1{$eN16ZY8shpgx53`25Alq&@8QmQp6SqfCwvnY-+=!wk6tOLDVi1nBDNvaQy&n zNY%mCu7e$U>Vv0()&v{Qsz!}Cs${_Q+u~lMu-I3xqbAAOUM0mQUL@D7IV8@$3JFL1 zr)rEF2;QZk)LGMxg_Hr~O2n8AcIYa`b_?P+iSnYaJQ^MB-;Yo2oS*wM2G&K#;I!+cSL7urXR^s67zFon7# zQo1M;vO#)|THtz|n2VIg{~9mx{812>}&R_g}i9tJl@V7{8dN>(ry#-o_y9FOD~$T=lHNkQVPAZDvTe4F;L&i@UnQ=*=rZ@o!CR;lCoD@&ROh z01N@_Oh$YPl@|;qAS~zyW*HCJFbKD&Ru07&;E;)2sS~K8ngFXMhd{qXLzm5GOC8km zOp5a6&H@aZ4HIu??#TxT$W6;*$WmB~*GXquoW%>atU~dS#n@ek=dw_i6@gfPhwIrB$~DpF7jIM0>NH<>0ym-)TsdwXsn+E-V_5kd=%p#9t=pB z)GF5$I;1O1Va6R8dn$JYLOt+S*#K}SE;Wj0Kl9ml-FfHt@4ffo6DQ7|J$==ap3GnV z@?6)zQT)LMZ|xz9C602fft>cU3~siH+-3r}_AJ!^0}N>k!&Vvf)h!GNmuA9cF4wgq z2S=#eaj#mtbUeMmM3ksls?mj9@4z+$%x{7y)1Jl%Zu0}g#Oq@_D!=lauqxB*03xw24!MgwS3?JQ=N%wo0u*tjoCIoVyDss!uw-Ul+l?3!B2#0c9A09>w0KC)(Z>$65m}9Jx=Pz1@}f>{J0Qqi zd9Z5bBs;c3lV^=G36(;KBZN`p%<7a&*quR8n;t&~iZ@vyQIi%jc1wZ7Em^GvCybFp zVI(58H4&ItDR1T8+XDE`R@N?sL2;_n7Y*y`1Q~Ky2;7bx2eftwSR?DtojZK^@XgP= z*>UK90@k;Jj{G3uUw{}Si!vvy=G*kawFj=aS+5mT@w=eKOV;wC;*xH~ipK_U@OC`X=T zS7#jxM)uAu6J-Xd@48iOQg8NRZg*YnRH{M4h~* z*4To$1n>RC*(7{oKvTY<^VB+X3+F9HY~=}MS_`6SY5I|jruH=x*#e!k>3t5Mq!=8j z!!ivIO6L=WEiY2vKg}lI;eqX8YdD^mQ5~>7X5;@Sryg_6KE9D3Lka^Y|K&wtXWmx0Ypd? z=3S-*7k-B#>m)V%QGeZvVfn~@NN>H__?T17CGd~MWbEiufmkY62P;TT7ZC2I3JuE}8 zYR1|PN`J@)5j%;0=+&rnMzW4cXd0JrkRjoi0%ifBDkhAbfnCTEPBdoJ)Oh08V&g(e z^5&7!x9rToIvVhKvq8qRC@L0=D~ZAfRDn%A2|(r6+}-0Tx-lr^?5Y6v;x*s^K@1y+ z1Ua$$BHoHJ%yhWv0X?RTW{`D)e$~wJ9AOov9D5eiD8bM`EVb}-;HyR(VeR2q_i^jH zrTg?9(4y)EpCUJDw69KjpPz+N=b1u0Yb%rJNe_k=HG?G=ofvLexPXf%T zF-lz4%>f|%#*s&UEd=G|%<8mJhgUA?P?cI;HR3=B0i4w{a6HwlYz5VvadaH*6|e+V;xc1QF$(}7+FBY+HQwRT8|-0=}e z;lT%sV799b+N-JY$@e1Cc?6(heSP6;qZnkafjwUyw;Nn&X*UD*MI-@?~pg z%j%Wf#*l_(js`0OgX_!+B$vvD(>JHNV$fWI^)wt)IERN92AIZ;RIohFY7q*9Txwz18bc5AApO_YvH5LX8`8Acovd&Cir6#=IsJB^Le%IYzYv**r~%XU;S!s_)e z(Vouq@ll@WHeu|s8G=Bae#`o7D6&1Zn7E|JvD#{al=Cn$9h(S611(0?94J~j>>D0X z+Z1doEbd^M6bG|Ox==)JBvN1eDw+idYH&urXnoo7W1fM_1qBmu>eX%9G`Gun?QB#G z;?y!OIvOmJhA#c2HL^(RTw8E^hlz2YNGEh9CyuaB{T$_nF=>IJNNykevz)SlZLVpSWTS%6V4xf$cKg4B^P$Y+17d7RAh2n7^QiwBoIb+#t8 zKBMzhs^#5_Z{ggyuq$u@cv>=CduK@HZwIgECEN~`pbi>w8Lv6l^h(ioZHsr`-9w&? za)bgkj{JXoYFO(U@Oh7Ac^-XhyLbM0dV)p*4NFg!YAs|uNQbJjLosDQX)<-GiX(ui zCRNR62iM|iC@ddNTI|zsms!dRJ7j<(2okCDm9XUMdhZgOTlFm;wu4QBH9@8(G?^&^ zT?pf@fxBf0urbZB>5Ds^c8pDWX7BBd-I+(E-j9_Q&II4fw)&N_&s56@CW%V}1}Xn?$@2b9HKBEw4BY$% zf<&_6Gqk3$y|jLpg^PliF!QgiOzu&9#VH8Zjq|;f=}kK%eKA;GiI9Okr`oDv5zw=p z_0NIYPsK43B)T+@9KsT-Rn6DPy**C7c!5sR#2^C#(WLbtydtiz_0h&OkrM~?aLxtf zJ|YY}8EJ}5pN$%BTY+1+Gi@%bcXe$udm~)z1l5|2Wg?YGjTnj50TZQ{!;6R!nE^p1AU2vVqH-s#&=lx?qUb@qi4WT!jpvS1rL5GR2lCE7PHFX;EkW zoZSe?W`b5@sh?eL|YZ@$P@o21H*W0YxUNNf~S_x#~Ymo+n z4=K%R2ADE|bGVS8UhYO{GCZtJ)0jv&##DDXJ4vf@t6&GRZ0h0BP7I)$+!iqlJ3&Nf z`amUc3veAfyJBk;`aKnqY>zdo3YI<0BVE5coW(GhrvPNEPwP~kDGK?x5VD8V=9Hpp z7G9*u+Plnm({%ra!fV%g7gA<*OeluA-5N!o-tibHmI!~obMv%t^D7Dy3>XuG#BBSedQ zLCdIcOl-RoxIy~`m3nbXY$Nmeypf3laLbnAw2Yg?pd(XGw#F(bDrc0>mg(0)HxYPO zxD8ve+Yh}5=I}@ddD*Q&UH=ynC6qYmk{JWct7W+ElVoEzqZmo4ZJZ{euGMC|EFuQw zm0lJpdrWh!X;Rl?hlqCo_>2y^=}ZO6gUgpJOe-!5J2}GX zBVjbW%#A~~iK(d;+nphH`&lN&IQCw0{y7&?7CUi;06syeml7&AkjduXE73Sx!yZ4!R}$Z-7zAbUDVFp+Vst}E94%Jn$ogf)!j(sZ4sUqJd*i_tD?>ryQ(A+QOZL~XcN z(i-*6Hbl4|69x!CnI>EVFs(U@v+aQRgDJMr%xDfq*R2zjL{Hpy*0DTJ$6`<=>;qR@ zUe{RwKOo$yoLAh7tn4j>yRb!E>wz3#oYSqvx732vfpW;ulfF%l5L7Pk`VC0qoi?DW z9O14aIV;6MRS0!)pkrc!kaNYPaFV z7krLreI{WS5}OMB7%IIKN`vGbwBT@mNs22!Z9SGEUrn}r~Hc^C8eQw2?TH^8np@!9y`>SZjV`F4F4Q0 z)sRE31&&Hat8GOGRVA0r0tj7&Kf+rsCJ9sz!-Vb4)jk4S9pPcN#tpBnau5|s$zW*@ zUSP|^O^Blv>DIc^MJENig4rzCKBDPgfb6H)V#n&36O}~U7EH+s$3C!xIf-x>6k|uU z#PBY&>;hF_Li$6{3ZVDE&L?`xi=l)T(@L0~$OC(SJr+o5sVk$D*QG(o6!{3L(n`A4 z=-_)xM8;ALvT=bT+3#pn95O73efF5Q$C4rvp#rq!H1Wtvve3WORig}aq$S+=;j6T) zFAMbM_Ms*{j!9-dQza;!I<+}Ro~ezZ@Ur8Gm6N(KMy5_0a<&P=KeOwoKGV31Yx4q) zL3RL)Y1T*^7UVW)H8X?3_1GBLhr3{QOb3SsTk{gEfb)+r9bwcUF2g`8eH1d>ER=LCN{K7OBR* zggRbZIB-7vw1!Gv>N>X{(BOr$%V23hOX~Pj-udcDYEMu#f683ES$tqg2Im;Sl zj73K)o)9=A&4^Tz*}SS%E!$V_)d4hFtjb%nPO=du1>888t~RQbX+kR67L2mAV7Qqz zriAuM(n&DsD@d~I0wfQQ@!DDCTvHZEq<#TMgv2{1Qu&D9+1TBjfkfR*ll5D#` zr|tCKVKi5e<-*D#QS4sGEEq{*>0MN1X7NTVh2zjh}CP7YPKw59pxi_9Rh^*s_VvhWvi>hzIC0TGb)9{A}?6jWgQY* z2+d7gj)#bN9B&HHXwi&3;1zYV%Rk=&wC=Y>6-Rj5Y2|K8ryxFO*o_H`awK85;;l}iC>p5K zdPd&+r%dUD8wO2T>Pfla3!^TVx`n|g6h%9rbqPj4+!_2AJ`{Uas3*nZX<{zVQuvgJ zQyqu*jcJ``Qd6wNzZ+Tafl*6Qn~mJ2yInKQr+$t$uvkmkZP0C_*@Fw-;@qGVNM2vG z48~rgLFr%oTEh?-sSZ_~pH5aw}^}!`eajUK#OW ztKVD_g~TDQiGxQKnxWIbdM}`yp~KF6t`(yWFJ2NnOm5Kb*8-C@wH}>AffAF!!Kip_ zmZ^^1fCkIsA&8-;XdUh z%Bu#}#grk>YDq3B>X;zq7-f>SUI_3gY+*w)AgpU!c6?73R2;fs5O$PV;Rj!VmxkPuRk^A8a?D^C5jz7lECsCxhCy9yU+j0k8fi$v!mrVU!ebz#Ux4851a;rO7uI$hX{#4Euv ztVWiq+l!1B$!#dgWW8RP$C?f6&7k<*u_UmN;RTEiE$B|_zXzv3%aJ?9*g|oXzSO+UT zg*q2TgtNrF?QP%Q(JBT(*pABN^)A~bINb|{t_{gHfGH;fHE|ra#%UMV8C8gYMqup< zVRAGZw(Kki=JkOap*cOYPX!9Dnk{4#2>{1TIEgakb{Zxku~keK9+GDY-7qM9yJ$Zp z-t9~rVOzwVWf(`?$_R9<)D3gW9*q!1lAuV7HfS_1T7+I21L{z9FZ!gFC0asQ4K&{6 z-cj#A-O#!8?2}^KDl1G0)2MnwC8=~QX^8v4`ba-8Eo_{UC><$>rIvIQNr2KwAA$hq zaerw?>r=*+?Ko<0O@eIXY*~}}G{SSA`E44TI=M8l91qlTjdYO1!h}qH-}Kye>&W;@ zq)nh)pZLZNm4Pvg1mxRGgcc;-5RwU&G|2Yc8eIpp!tuU? z>ZX6$h(4m&lRLGE+zyJw5+aUQb7mR_X?Rf;IiV1e#$F{YwJzrhp!tXhgfKWWI)@IY zw4tyH|0)KNRg=;!{gjtD0o2hsK>=4A3W$TfEJGUbIL2V`rxIqXu&7)`DUao=9JDjz zM;M^OKWL-d6%KVN==Qn@D)M2$pjOl}$34!!>8K)GLt2@#d{sSJ!CHLoI;RLDs$xw)75!e=-6JsmeGpm?psAB^G?ehbaJ+|Af z%{V!howxW1?S2~qasz!vWw;nJT*?*AV5<|d@nbIxN42y9$R<34O#|dRD*z=06TE|o zsnP4Y>hrNb;JRl)K@CCJ_L>wSJeRoO^aPr zRKdZ9Q{x^4yE&F&JKN}XC!z5Xvy_$?@Ym64?5U#&LnC~R$fY9dARF(CGMWCMhm*z_ zhO_-fj0T5cKX~f&sWWGk-PuPUJ#q4sW~cS@=wpwbK6~c$nbT)AJ*TS&k?9hgzn(sF zM-Lr7boj`T}}Y&>aa=r|*j0C7JOm9SVds;MKexd|94`$}^`7Jrba?L^XH=J9$c>=5nF zV>zkN+aonm7%ocIXT+lwG|CZlc%ZuxyvFwBL?(ZQ?6r>v8+oXa*+9?yi`1GL(-~xg zMd%@#pb6A@H2s9eQ5Ctut7VAQUK0hklweZLk$BYhv23~1ULob#`puygA%nOj8`zkz zM4;L`Q~yuE1EIm7Fj8|e60&Vq>>Nw0Rwg~ji=Gp-|0u-6G)z0tXm?e;?_dzZ8*1>F zAzNr;XP^)JMJ_8WcXK?J%^?sP*i6ExAP}jL8d*0zO$q5a+)_@B z15AU0wtL-XyO*iy_4t_*~llQDCABMuH_`R&Bk4usfW?JJphTlzyrJo zF@hOu0(O%_8&6>tvF4&|3xc-oRB5C(FkLVUyr+ESaV2VGgFdY0Eps1*hN0f*_Dm|A zjdPo(I2BA&6?!M;b+LMX)n?w~55X|^N^T%hjqn%6dBj3EqLD<+hh@0p4`F~gL9zk7 zC{Y+@PX?^paS$$p#FXPA*6_gxAAIPMhwr`jz6T$8;0s^+;)4%8c=qI}@7!_w_wTvq zp$8s#@R0|;chB7q-~ZqbfB5}-?|ZbKGAs<2UUtcqS6zDS@P!v$a_Kcsee#p9zUJ7` zBTsqCQ=fjr(=WRClB=%1`l;7kbNtw`r(S!_<(FNirv!Soz(vgut+|HjGQic0i-Ah* z^POv1t&-QZb9b@HyRY^(a+#3swwY|omhys1VHwTSEqhoxdG5VGEx@u9go-O3`8h~p z2;RJTup?Ps;StKqQ%31>eU(OkpCBW9Ng#59e@pDrPLbA(uDCpCx%%QZWuu|*@qYbc zhMG`Cv@zL-Vu<|wGjS+t+j3ZZ#(`4o{DSMf59;~#-#k=Qbi=MNQB`Z9A;?L$4ZIo6-Rk4o%OXbc)icxMlXXNqf=;1}%&8p~I zL|>AbgCv-_!YKnYr13dTSQ0ylr=fvpfMEIb*)*| z*&U#4cm_i8-T*@y%b|%~F=cb9uWN)CD?3gqabrSbHB!rR2&F8uK;qgwU*m8T^p63#Vb*T~*B!R2!3jyl+|H609gr9XGmeYA)^tdmfB9XVR-IST>bO={Gyqo= zBF!ZojRZ4Ufjb}pCey0h^A13irc&TCid{TfJUsVcGE1_OH(<9Pl>6}&Tay-FO_}9a zpODTc?L;1>4gr{ut1V`U`4cIViRoNOR5-90w2Xf*BSkeYvQ1%_cv5<}bCjNOG& zzuB+E>Nad!Q1P$RG4`O-RG;hUR=wYBC!$?Q!j5zVHm2TwE?(<$0T?W1ha*c+Y&k7` z6_%z=U4^nF^&yvxd6Pm?468}22iRpTt8#2iL@;`5w4HZ}bcPOm4>r<96?ww(83W9z z`ts4#^e0cAI;XeP)y|xG_@Rf+=w5o}>|-ZS>RmXAb%)kn_3+_*Am`u($B!#Ey|I4m z$dL;!y3lW_>(#d7bw!4}16zG`TrO5ZS#W+7UR!SGbeV>2x=7|wBefmRRfS1%+%*h9M>Vt=TnPH!002M$ zNklCizafQn=w96=zBe!RY!z$A+sI5yis2XG0CaR6P4&^Qp`oxjLTDS3y;sl;FB1z&nl3wJ zP>(@8&*>aR!?B2_U?0hn(LOsjtlp0r!Z`eNbs8eAhhp*mtOsp8KDOy5@dmp;dFtdn z_uO;m-FMx7`|ZE~2Os;!H@^0f|L|M)Kkx%7FFA1F`LB5KldpUBv!DBdr`_<3i!ZtC z(n~HqdiAQ z=iYqNO;=ob<<(bR<@W}T>6w6DLet|>`A{MJWe9n;;{>@-;GHVe6~$*-R>4=D@Nbu; zX6{_*ew7X%HmFJ`B_?=4;{$`>EWvf;jzKE_p%yv>ni__QM);B&+qaeUZkik2C)&Y?bYZtt98`^#C zK_smlW#~aHHB`gUb04Oxm63Rs1M6g=4j7lz-JG{vy@~6%h}*ziG2HPL!>tKxT2BUB zG5A|hJ@K(A!o8!^bQAwR^Ton0cJUpa-U0C2QNoWLuaNPufT+*%tN&q z~o~H^%|IHs9kb*7t^F2PSb7hZV$AfKu|a@l2<9zAwUZ>C>%$t71`ebt2*U3Brqm)>yW z^;ceT)soR8}snFcxo)kS@&*?V6ya;6Q9q7+FKd&?>+rO``#s)y`g;Iv}vJm)f#MMTNFB%Wz;BgpL)> zqy(*4uwiPL!;%s9?Ze;@4jN=7s-ZfO@CrIk;iIWH4Oovk;pzNHnt4tI9w8!2^0P`>_)z^nBpXJMX^duG_!z`Om!P|M;h8xVzC__<|R_>NT%= z*0XMU;Y(if;vaj_6;Hb2_|fBs4<8l<4)v?Xq}(%&Fqg5?Eh{(?F?3iqi5>c|(|IgL z)5oPBam9TF09?PhA!Ae8vKkT*5;3&u2~a=@bhGC5_2GXRgY9tCgYNz8g4zZ$fK5=@ zVtW3D6SD&e&1Bf$Oek;3_~FDF1mVcE!^lo$hA$u6)#SIzH)B&PJTtIlcm3OD0pDoCQz^XfQ(3e)=rl(DhOQ{SPyqve^(vO1mzn`Q+CgT`I9I0X#VcI?)>UkzM@<2@BZE&-FNTZcYNix zdrq8g)Pbiz{e~-_{L~Beu>SHV>96IEA3uKNs6IM-M6b0SJSI!;jp5 z{|_F0 zF|M55@$f++{rc2kcLUME_c%|OQmEN7$(m>1PhAy70vFfJp~0#~F|9}(h!+^6Vk#FM zZ7_@8yoHU}E5y=a+B6f#((!g5mG1ojGUP`#x`z$}_?#lU>En!z;JjN0ZaVArcnp!AOh11yOec$S9& zZKyRyXJH)z*@#v(21=udhK9KnkxaEl-r42HiEkaoRjzq^FEZu}-F`6kTPYR9xs!V3;ndkf zM-K6b-ydP;tw}%DSA_iE=ZZ9+&nFH7(W#`UsGkTF(V={lK=)=nV>qaHIQ53Xv7<-z zp(AMz9XfLK$U(iv@$iWg5B}hLpZ)Y_zWw#DeebSs|Kaa{^p0)hO>MHx$a~Or}fqJ|X27?&1k{R{PJVzJOV3*SdskzI~9H4#~kSHTH zK)qccsnr*fyF}&y%Adc|2ze|$*mE$Szdk4(NsrX*3=+C;4Mz2+5R{VtyT^reRr)lT=a2UD3*Z6kf!1&#djt%;Fww)37@P=bpAwK{A z1F##>$$jMeP$OaZ%|_gpOmoSy#)wI4j0Vwjv{w3h=wVaF7V_o}Z)16U^* z7kaNVe}t<=Bto?ZAAI1ucYOEu?|%2|U;WB$w|()8U%Bl=ANb9vuDSTY%`d(688IlhabB0uDeg4dhDSGet7rYcRl*ZgP;5KC;#a8ekYFfqS+hX^rlz7;^ohI&hu`5 z{>|54d+kLR@uoqv+hbS7NqgdrJ}R_DYvwCVCA%uUk3~SEYI$1jJz8Wd=Y}AY<(eB7 z9&u!}9us3ES~T01+ZER1;Z$k$8l|ovyqhZ)BNwK!bhk;m6z!pQu%vrigbul2yXZJn z@%l^{CPPHH-kwWvdtF&FSQfoEsphaal6XiUQ9c22$GDK5XE^;=xmQy=m*JGP#L<U&!voiIfDK{=vPN9sMWsmE9#czGuP3BhzER%|#4C7g&l$?9&CdLPnjZp+!(jiohf07pcX9Q{W)kF;w9QL|G$_G|Adhk z_Gg*E9lf8pKY{TuF>XXo?K*$=vzWV~lzTScuFB-4N9UoK*#N_pLCc}=NHXLI+955# zSr^AXHS4t4DmXMg4<)9RHj~|BD?=v+UlNk%`g&vZIn^~@TPXHbO_)!I3MjQkXMxXX zX7LfJNmUT`IEtk?%{qS=XILj$MGl+pEvP1MN&#PcT3CBn?&4CDy$xfZJXQrllxkR+ zU`p5chublTP0+F=dU)I>2+BE=l4{mP8eQ=9NJ2L%pZ)C*e>5bodG)KGb@L0K_kth2>G?mZx7VL^`Q=9sAJZN1 z!iz6Hb?WRvzrlT4FSDIHz|oPISk~Ee>KITUf2K$w=%qJ32hhFMcWZqep8`C4@AvO} z00@Wt2@WL!L8S1kL^i6EMWT`#lpA8qY+i>jnA_xxpjE?s zyU#6qijS&ik?X{Q zmw4Ky`*~Gp$>@u2%m*~P(`TouBK;oZaD=}0_TZ^ON6mEPTk%aokM;??iix4MHe7JM zoaL-t6#w)o0WQ3{R7hvMF@4~grB9SdLn6E)fAGM4_ul`7uYBR7ANlAD=r7x9iPo2~N7n)Kv{qWS?G5La@VC_-{ zAmk-+=%F=J8DOb9odn|YSK8UD2;-HTrMB6;bSKs_VG z+Qk~8u&Z{6B&`M{=Aj&O`9}%ZsSmIt1Shs?4!EG?7;(Nhp#lI5t*t98m#Wa_vexx$ zW_xke7&_vFD8Rh`GO^xf%W%@P(B+R_Q-KLi2^iDWZZhxsEqeTYu8L9BU}R& zoBha>8;TmP{Dob#0VP0=8ErU9mdaNAfpXk(J>E>DGEhrygxv4Ycqgn&6>PEX#zaON z0Hm`mAuGaS$9H0p^_UP4ps*-fgp-x z-V$bKc*|S2KUG0*hU*J3czgZCWB1*6?`Lnj?N9&oPyWgO{(s(o$G2s9)m2yg_)om$ zX*b;T(wDyU+Usw4@>8z4`pH)vK5$51kgadl)_vxT{<8NpujlLbr&}Q0rj2u*d=hax zlESxJ^$E_Kjo2g+K=)hS^7Yc4@12q#IC}Jmtn{?t_V0ZA7k>V~z4EFnU-QPl^wlqY z=?kCxv)_2%2M(NiSeSRd^PNBaw!d=o%`dq5`OmxJNtgRwe=34I<>vb`V}8B544KoX zQ+;Zb`SvKSA|tJe8pG@z3TqVrrx}$dquEaU7U@u)a-Izo>KVhB*f=vCs|_tCPSEVa z!eA5iLIt>RG{Zi9o5iwi2jilSZV95450wdIx)+X^>IAII;9?tu1lnIb|J43wjA;VO(b7Il(Uu67wF#Hc z;FwJn&TH&EnijcUUq7Jl?LT+u(|L%YOuAlwcm%a4IF2DSW-p&NI{yM-UpdlKoIe1z^ zX4Z13QKyF>q)|Ffl=|oRsgc9Bt>u;!e1UbTdjHtPW@9yvI3;KMh_rVR{QAX1ao5z2 zSu|@2SHp~bGD@OmRE9MbOf5$ZRzQTSL^vq5oCG;s*-CdI7a4##djQZ@C`y=O88#2n zrNtgcaxao$Sk0NuW~H$Zn|wSIEirO=8~$TF^6EkNL#;uvyWg=7E08iwr=!~pc8*E~ zo5&_Ra!>8T+ZBi}K~6h*gJis(1vcC3VGV1?TfiIdDNW-lmTh>1xLV47ww;hzS}xAM zw2`P!8QvDx`{M`nfcvm+p88UYPk;6^AODk&|JkSh>{s9Oo{;_3cmMU5-16F+ZhGGJ zH{NjJ#g{$lvP<>ufZo|YqOYgYf2pHyxI3)>?~+@s{<2M%r_+oj=Rih|O5T{bfGHW{ zPKQenQ(e7;*BzV*e=4AV1byzX{#y9(p%W)g-1eDIJ^bMPFL~8#4<9^q*Ijr1;0O19 z{?niM&G&!sV}I~rF+BaL*Z(I!_p`U$^2+Bv=Q+=K*0c4VfIe1y^0fX70sl!K%jS^e z#U5mWPfG22jCfEG-r7=WUz@DKu9Cx!4AfR5Tacuja@zy#`h#VR0i%5Qxq^$3A`a3< zZt3HyNQw!hew<|yjV^diSCb`<0I|+UBp?TRYNF?elG;@^f$RcHS@>pOn9+=u#VJ%v zGsRolLTQ0(SL&^9J8S#yr?y8+@GWZa+K*5MXlLN_YqgMGZPX~ps?Y{+Zzj8B4L}RdTT;2&}v~7-5=RO?u0e(9$kb^b`#O-o8(Q@g$9?{q+ zXQ#e$QzsVh0iHegOQdV7=XF59f{?JFM>*6H-qDym^Vw&j1pD-FUw`Z({Q)oKPHemnRcabCe?DWqwUy zblkGkScqH&5`rK9dj(|3RYm8$4hm04U9$8MNUmyU&*@9gPMmo3hY#HU^{;;EgYSF) zC;s@uU-)(mXMH@!InF+G^bVBom1fJW-8Le!R5GNlBlRU7T3n!ft#yiDDR51!^3E5UHx)W zxn}kkIgU7NgeRpkTQXvfriwGwb~`W~noqpsWYJ2P45(h2X*01kGTlL@=pEv2Kf;)7 zwik{&rqvSU*;c??ejwOV_BI%#%OF$%M=VKEVaTcxf0Ja502nmE?Zjdt%wTafhm%hu zHOJ__x6tDdh&NU??L)o=NK4ZB?s315T~;uPJ$P!@yJE+7WY?yuirPM5RRt?b10Wp) zi;vEvOFb~FF=HZKUG0q=00=+GQ14~|mLnMlqHt&y%4nS;-;DxU(14@Xm6J1{27K_B zr#TOX;~p8&Nu17OW4b;eO)xnMGX`Va=7P@}hix3~dXN91_F$-cP_9N8NkH1Pc_~N) zLs1p69-D6F?d0l=#*_;NpJeeEV*{~@F{dLU-==(W`mg6OG=c!#M5G6ve5KF1gC`z7 z@xvef@WUVdoe%zp-~7$r{Lp>h`~K6fyY_`I`|(%a`nu=8_!ZYa{l?2Ky+|*~>p#EL z7ki3HR{DI7Zf20283Ij8%&K4Xi?Io_~1r#~e=ed-)<_n$p;{DPwo-v6NfN6)+N_|6C4|ADW4`Lpl; z_4msA^PY3_TYvhm{LI_mdfjz5UUTiW7hibsDIOD4gmQ>0>eSa0mnDJX*hEy-P^QfJYIfoxKVu19OShaXnva_{VswcWU^M`$?)#70*!_5%(HU>kaJ zV>a86;ERYi>dY~zLRr0#Skr8#&}2}QIeKR_oMSdT$9%(Nk@MF`EKt&QV@r+sO4PV` z2Hxv9B~7yFQ3Fj5L_0j z!y@;NLoYz+Z9kzNJ@J^n$>$e;={^79L+}5@pZ@7nuD)9D_`T-!Z+^+kZ+XhouJydQF>GcB_4Xk7<|(gL94hfta%(v-HISBvD`wYm+cr^JW#AIl7EdI; zFzkpkjgx&<)OU|}keumKmReojaOez$kjywk3WvbnhGigNbGpZB!lg)yNXDs3ixWYV zToWWurW)DP05VV+bRzR&=aSV9%u@lC{|=lOo?rQuKl+2;7vRlrdF#t=edBYV|H2!eee>m4Tyf;s1^PaJy{WE6(no!c9y`LH z)*U`{Mjx@&{mZn6wa2)u!Ov~LkvaTwW+4I|#7Y)1Xzn)jiWNP;Y#E7lBiGHZo>%Cx zyOPk?cj#%xImz|?8{F{W&-s12kc<^=9@xDIU{ zy&y(9FH|P1&TD4U%HLW*ZV85}R9pQ=BuQ!({szV*MV{tEyBX|Q5+A4Qa9ZFgVl=dx zs99O^NT%3SEp$Dnb(@Ajv)y1!vpImUyN$Fbv!X3gpRL#-EQ)=3#J&k|!6&-pK5Tb* zDS8kX7Al5=siqy*pc;Vl)nOMYPqkJ%QMgD-0|RfPN(mS;em&AW(MCc9jD`$>8hg76 z!%4wR2mPuwRx@1-Se&%TJ=PG0H0nD*@R;j>Zq51(q3%})^qw2bq%g|XU-kH;HVNmclzwz-@D_s&wc8bf9YR+_(LDK zERlKgwVST}w6|g-xAvBy5i?XV%qLOb(?C6hbdW zGdLrsW(^TzM04drWj=|LzBh+*T(DVPn;BN4j+$w%3SpW)Dv_K`IjgJ;Lb<37G^3Rg zk4SG#;A>ld@5--N6__VTH zK;E93`H4zpR9yvE)+q_TIfsDQ1A<6$b&Ct_d9+Tjfzs@0wh@4`SU)11P~?ti`YWZq zL^|yZoz^{?fR@bO{&5pW88Io3emTbK1d?GNw+^%RbqaKO%_}R&efDRuxazG#4 zf9w;V{Pget{_p+Lul~xXKk-RXzV&C`@!Fq!>yN(V#%&aB+B`mzB=gK>2tivug@6?sD}#vgwUx|XY|!VXZ79yA4B4wzlB4C zbB~^Q=xbm3+NVDLhadd+|Mv5r{gk-h_SUz&?QL&=^IP8XG^KXz$Volm@D0_k%E_Tm zjokAS4CUvhs%oO;?oEuTrU!~zBFEa>%(LX+j8LlH*At|eJ`bTYCUC^>yJuQ5= z98*ITmjuYq>!%d>z>DeQA~qqMArQ$z$dKPQ$(oo{T&{~Ijsrem_~_sB#MW%6mlm;U z7C!)5<9-QmF&@LlTCju7bQAfE!HF)88Irh~HlAzX)F@F3va(a$nqxy0jzlsKb$U!! zmKnsT!5V?K%UUcbcm&P+a$H94yZ`<@qKJ^xaFEqu|FF8%p`_>W%w>es#Q^{>Sd znQ>YXh$0q3$fBXK35Y$M^g zzZ(J!J0I&n%*BkEIDrmdF0`Nse06lc!_ibDvJzA$+l|Yijg+W|zYcz2#$d}5n~miJ z6mPNij4ePCxFE^M7yc}t#6-hy;${JAVJ+Jnj20(-E`numhSZXE`inICgKw^V*ak`a zFp|4t<>oCx=w8&-YdCdOTjk8D1qR6Z&3@PoIt<|VwtaLW!rS6;{Ucxu%BVV5aAl6= zkN{U3AD9~o!gZ`oZE7U=*)DG*_bY=*rC zk+?!E4*cGMC0~*l%+*P@VUrYmJ#!z5a+FRmh|KIUpJD^_;bea{4liv?k` zJ~Yt1_i~Wdx3b9RbiwQr^;~`M%EfzjQ7pq;9mOZOAKHz8%i4>POMwUx8oW^0cD%nb zf-LtdTDr7sMpW&E`fIEOj4$20^xs(C_JuF~t6%=5fBDb3YBTg|2vR>Z0|6^s9(ALtyRvV`)Kw&U4#1-U@$%XqM)K?Ttre@D z>+27Qj~_d9$9L}dN zJ54usEVEsd-rDc$Pd6kgtf?&+G)id>_7oIv=hHiW)02nvzv zr=!Cprzx65D;NW(=ln8`O_I)Xm{fw$!J7!pG>vv$?9Po$S=jBlcnH)h9;T4;n)@=3 zko@pIvUi@YJ7*77*1wU`fgj%g;2-?QkNr>o%m4TvfA4q2@Uws8@BF2=zWsSGzUA^O zF4xuOF@5at?71T{`g1J(rzyAJ{_PLG?|r}fTOatnkMP$`KmXtT{NMVUf9tyIuRC(&xZlBaiG9uG z>etOqG?9PNyX~%y72sGRUzxI2!u4gP_>`GOo;o=9CyLeT!nU=?aC z)p!!sSPW6X7<2JU63U@m(jt(giA{~mGx+m2(zc`aSJq=H)9Du;r{P0bQ@i+FksF9z z1kbV9cbpKrT6GHw^5}FdAI>*pbovdOuvMvI_fsyGh|JPFcIM2BuynKYJnlCM8;7&(@+~M8B|D7jqM48HJ0dEEjy~AwgoZT;`SpC$9QJ>sgRi9sQKm7(C4h6RIK1fx7}X6Ig% z4&(9aD_k%m^3H0Q7FEluFRR$^=$H=HeRQQ)M@~u_7MEfi(TQTvc&$9eIL(HME)?Z+ zH#A@5UBCmUPoDnbm%j8HAN;`o@C*OziTm!l@!D(N_SgQ->wfBO*WdVz;}>46|HVek zdI?HT0Q_fl{zxuc$LD9FAu2aElplPt77E-s=oX^$jL>B_tV%lob0@%pfRygKstUAsMDDaP=3#xJ$mf$J>R=iUl{Zo z@BOt8{`#*9ck8Wh_^i~OFv^PYyy>aKt-4?GWHy))hfqJROMvwPcw;j z+omL&iI9l~)-Ioi+e7WeIzd{;$!59~z_Sqfgjmr&FNKb`9ZzKgt;?ZAy&+OEXmiRY zbaWkdOb8;nsjwpvL8$#Npndxe#O$-5`TYAn^nri;5C4%)+*iHg)qm~p{evHQ@ynn3 zwCnV^pU>-=nA21Qe(l{pHP5CLnP}0gLr;EsrJX0;el8HtT#lq3t%vk}8Nq(U$=4Yu zEy-oUr+r}5waWZ@D^oG#S%I&4!f=(~@+MncDK{MuN)#)_k#ReU2UU~M+N&V*mzx{z<|KEP$f0q7@Z~TeB{&PR~u6MrUiYu;oOkaGY&pkREB_Bq2 zUECz(udls7}H>OrmNxOjcX?-3D%RPtyyQb*aPt5N2W|Xkn>t8wo2~hi`5uf z+ZJtXQwhuK05h2M8}TaNBwif#1i;swkVrw0J8iF&Q+kbL2QjC1yYa2OtA14sUnIIP z@jUH4-i{F9G;OqPH5zxr=}>aFj(_UX^K{7IMV!~JLV6`tn~ z@W}s&-1Ft2><+J@R<7Tvk$^A=6$cK$&ilnM9{uZ|?wPvfvSrv8WOw+?;j=mg{V-Pd zOJQ^$1uJKpj4|I7d4Rj+={#TQ=0Zn7hYybPI!vqG_lAT_kG zDj*w8(>$hh1>rn&b`A$WV6o1@mRQRM-)a)MqyXG3)lAkIngEq0CJPdR&c*65mU7z- zsxrt^s+7&kF1YDN@7PHu7IjJQ40x1ONp;}muvs$Q%+}ZoJ&Ym#e>i&&c;Bz8%=_lv zdv5AYLP!BpZz}1bgeW!?5JBXlj06=yBS;4aFn|FG5r!i3zSd!smPiX-sR98kfHVau z0mQ)qj1+a8p`_gUKHukAYybBDoC`0X+2?}e6=>X6}%=O-Vls9=l&9-d;39$O?5JW$^7!> zsf+;OD4uR|1WQzG7l%M9z?y4-Ebt^4SeRhZVFwttbdhDUkr!q2m&BIzr8k!yL)XQ& zJ{*OR3mx%nb3QAW&&YrM8#lcBJ@3Bis^9qd$Nu`(w>s*w$2{fEKX~`!Pu`)I!1Xcz z9Ob&Z<IfeDSSTFzwhtbrmy%2vpMshf397Ffef#i@(u z6ubdI!1|g4?BE9|39*b#M&~#c zndnTs_r{yP^|v4S(5qhhg1>zCb+Ui_;~#hFr4Km&qVv|a9=LnoZvA^jO{R%uC=Z^k zjD;?ro&{Hqz}_mB2s~5S{^VzSPgkQ1@TUmN8;a1zM@%A&5fW#}jH~at@(h>dstFp+ zYq{1mm_1aEX!aJ@QOW|-4Fk(dsTiF>&a;ND(6_l;mLOZ9fkW*~Dl(22Xen%r>d@Nj z;$T>jAYiO=E=yFko0dEvaa!(R!!IH>i#H`+kf;Q$PC|;Lbm*%Pw+JfamUbHlg4c3LUs`o+$(Rj5J`{?`Jvmp+FR|zMU)$TgjGIWpCP{;EcJJMoDmm+x8IVOxr z@Cw%VSrQc$O6Qcs;N^E&GX@3&2q*$c&0%S8UcjMNYc%W4hAe(HIXGnN)vyH>5qjss z1qhji@gSL4$|VNEP(tkPsO%+5Sp>I0SN+;(7|i^`1cwNl$$$wisl7Lk7Yt^zfm3l1C5dZO5I6cH85*w3%^Wk^SqN2V=}o1CG(~A;7}dqe zDCMWevjMW=N*KiN*`29IKj;{-bF&VNDPA6L7F=LtJ+WjyJ%1n_Ui?yr-@=}EQ0_NX z8CgD6sHfr5g_qw&lHQ8JDj+K6!BB-&E7KDB^37V-cxJ}b8^Pg})0#=>YE~hJ7D;?` zzLs#0O!3?m)4C)u)2~ByfRO30iS#}FpSu3~XFU6PuY1)?PdNTI_qp^Je)t~uIrnyV zQ0RN~Penla)d9KJxqxtdKC{1y9NO~lC{%Sgw4~Sbk;|VVaf)7C1?`ljhxE- zTE11vgpVu&6rIj8qEry1>$fC%9fBjC8}2?R<=9UgWFXWQ0uZ4dfZ2XTP+@{8@;qJ8 z0C$qBf_L+--FvpK@$JmJcJAJJ^Eco5<~P0lPhR`M54`uVqYi!13tn{bMc;eMsVDBz z9}n-_d!W9S0Yf`b&oe_bmN6U2+L)@O1LlapIcsG?LRcuC-jfc?5^|VH)OSv*{kDr~ z3Lpc4O+8E)$s;Vx2Sq(o*3hv^u+9_S4Ih;w@#3@yD^THeJ8W3*Xd6AX711P_y0TNj z5itwt&uawyQ@MoonnvURe@jRcLtBAaFbWT}z~jab0Z!AQUMw@9NFZFMRIMxsLQ&5JrR zYDGko;vOlGi(NzlhHz+N3x3jhH2Fi_MKA|zcnj68A1{(QCQyYe{z2hrq+E!)=Od_N z4FO5n(l6a$BMI3fq^s<_f+dMnKxl2D8-4Sr)@h$DTz|g%gS;_Uyj2qUZBTNJq@MO9Oz53^;4x2udy%~syQOBje^U#`($X zD^qs5v%*bi%?Ca_0x<9yK|M|k9PkHx{TttW+uPsq*L(fs zNhhDIkG#O84-E2uKYUVfa5%$7+}LZ9fKVC_z;FVREs52^#6Bh%vQ#7IM6?75w6;k_rsVx{&RRr6a+wp&j!$ZK%O4B#WPy8nMWjEK5{3OSw0i=ew7ol)a0Ww{ z@Ht0{n>Sx|COhz;gLa&G+w*RJM>+f02R`(=*S!AgU;kf69z7kY(AZ&D~d zLL*1W!<6IPeS5atI;ReF1k^J$FqnBhg>eEH&V{XkeKwsm_MQy`i+&wS7}JdmAc>8F zDG$@DF24*Tvtp8#SP_)oO*2er5Va8|Hqga3@!QN*3)Obl$;2C??lJ3NEDNiL5?h)i zAq7EQV0C-Nqj5axE*RTn0o={(nx_b5*4##n%BzF3T1BY!yFP7uWJ{wX8?~xNZT^@B zny`%ywme!pyi3)V-AY%^)#6CW_^4D1)1sbOP_g|G5!81q(%bENoSu>EgALL}5qGK? ztI7B~G8c0HnEzk<0+2GP*GXYNW-S_V#vx%&D)%)`P{FFtk%$QN5~yVO1Z62a48$n0 zh2Fz4$*LtlGYJUD#JpI7L0L&-mym@gO>REKjw|b^#XS65h%8JpHZ*IOKx|PAD3e@z zWiA<|RP>zT6d!P7R0Z6l)po|AiP4J1dI+%fGMgbB!8)cXAZdJG#bo&WN9G)$SS9=^ zQ1eN-cq$|zYAO73JD@C&I=X>5xm-d~t_PO(x_`jSCO_@WU>^_`*HwrGmhwr>8?KmXJF|MI$5T>av|`}C)N z;yyp|Yfru6PItKD7XKl{aBIgJG3zAA^*8~R$C@NmDvrY;FBPhctQD#S^eRx>8iliL zgCq~w3OWhH4Dlvm7uh96lSVoW%V|6;fbs-bDi>Bxt4zNq(N=9LV9f;qVFrGoWRUow zSRmn_;*Hvl*GY@B0cl& zmD0yZy5YFc97NwV~{7yWY06F10tcJvNR8|Ta zcdBlgE6ETmEQ!V!fLJ0kM{5Kz>0t36>*{rVzCn23zAt?7OV4`FZ@%Ea|NiM`oOYi} zFZ+=n{fV>AJBKg!+_g*pV`OdXn%;Wcb@NW`A^k~`j#HmobVACea(GleDP`d}iE?l% z98M>Abs{v95(E}LCDO&z2MS85$<$ECtA6cYond(IflHYlfMi$$dQMahWuSLURr^RC>S6oA8d3;>)jIlOLdL(I>oncyy@S+_NAx& z@-MG#-}aFYe&9B@KJ2o~9{Y$#KH~7hk2>U#gY-8Odg3JRif$~Z$R!g=#a*G2K43I- zrT1x?feMP$<|7;mSmUE~7I?C9v0+YaZFy|)Ag+bSy5cbewZjQUtnkLa1H{;_XuEHk z?^NN})DEgF%P+AfSeTb!5`leT1tub36h_IYMiIlnFG8B7pJY4*QAVZuJC-5{tV6(J zaIZ2rq3GC4=Jt?YFH1;Qrq_YByyLg^x+)lxh2Q%ekmoqQ;&(usg5Y>gTVtlwNC&;F zyu^_NIIl}H*|2#Qp?b}UaOrQk^2(d^ zC>X7`dVXLzVvm2hwX*8iNJ2Ojk_haPimk=HvO3{SFZ&4}_Op0_zIpKUZHpELtiB>fkRWO;_5j0G#Q5Kz~THhEucImkwv|Cz4sx9krUY|wTJ~&SJ^u3&X>|>vN z+EvfE>S zPOGKOl7qw>ry^&sLH20)!@(hy%>Y(7FI{xpev&bIKaJ#o)9VX*9{$a5-T0nA`-{gu z?(uJY{cG<019y4Ulb&&p`~0V4k2^-EAii0clY)p;_%o)hy89$EL~-d=bClVT z9;d>b6O?{bJAQhitr&svNQmw$NbyLb382W(Z$zp~20-nHK4&drRN>S@OD`Sy=9FrQ zDuFqVaeTp`0A#9R`(h43*@61Z5)v1uqr~-J+VwX8CWb(Nr6m*nnbt)Yf6tHn_5Kp4^KX0mJHPssf4P;)akt*GWsUzc>=U^R#O2epUD+89B~493)DF*nlL<~5R>+}s zxE{rtF>ue827c`+Paq?f%I@6NlxsTm8(E0dXPET}1b#mfb;3rH_|uVFjx34SB@|;ZQ8bvswE)q&;uLCKrAn;o z*#8Qj865`dK~p_9(Jlv1gVu$qXX#fy{pnV2NI}f{@xxvgN8mmE7Ol#O$6ML}!Q3ux zOKg`$`b3nWnHH$s%n6o}=f<-of#EWoqZp|~Xe~H?2hLK4d5FrY79i0z}?S!#F4Ap^ikgFCp2Uqp_&J$Ji4s2SA8 zjZF(t!fH8j^~6WE1dAo$sQ>^#07*naRNR<#?RtP+Ev(I!yW@~^L{%188=`4r<}!8= z79;S(8iTp?$eNj<2c?^xH}87OTi){YtFC&>o8EA{bI-ftxzE4bkKOCIV~^7n<>p;G zHI=$E*4Y+=@@XC>87`}!;*OllFGY@YHB+M>uBmE$wd1dCb*)3SMF>>BMylg0nqow# zm;H6A^lSeD>(a>+Tk7@=UP#uS2Tz^Q=nK&L~1 zk~cH{W!^3CA;CY>5hOgb+#U zg&w!Kg3iVM6K5v?LBafr_-N6c1O7ukTh13;Z}t&ZaD zLEQJz)$t8VdpCAONZ4h)(cwnP6bedbOHxaz@QPO&Jr*CqIs;VM3~g+hPGuprIP(iq zbIf#-T)9Uox2Rm_l!nYyLF$fz>Q-SbxdeyPR-67Sfav@L9(C&5_7*1XqFre zI@*a!|D^Bv&ws&xecp3E`jHPk@F5TX#Ya8i!aH1Y$RP*r+@-6oLX$9df5eJKopJ+OUH#sukrLGA`hpUtQ|>MsM;N8=dLwm$4F5YQhh@940wuC zSyVBakg8_e#I6v!#5^vCjLv}BV>w2ytP>Ha%2VLr9g!o%Oh6V)sv=1wo;UJwv6ewr zpyjO|mI&H+EH~C|1lyu@D9g|^l2OK7CbB-1htmNmNtWK+VW3Nbgf_rl{KN{1rCf0( znF@GHs54Px-;}?oRac<4$rNe7jkzk<(V98rsms+u>8TcDOBzNr&d@C*mGPf|l~5ZX zwo(xgxcd<}?UinJLFEb5HqFo@%bAOn;;GF>w?P6ZRGP{8Fb%9`c9J5W@n&$v{1R8r zp~3*wuTM=dbQXh6kjiy1nrQ%F&_F0H6(_8WyR!#Vfwp!=hjAJ%h0T&pw}6 zs9lrO2)e8YmR^{#qr%H6D5pxWab;X$wTz1MZrX?nnh>mUlw%yW8XAnf_+v<&UO`4f z>|T^9P)sd%goNUJjjZV1m!*L@-FajIz^1SM%U3V| z^{2l4B`-Sp_~Y*X;K$wPem`^Et!|?a`tRXFD=f>QkocI8Zi4-tJ>grtnqBcEkuqZ4 zGUqUeNO--7&(iXAK%YQWUszqN^!ILFbUTW$R?yE0v4ox-t&2%QSU2zV>*-;5+ z+&cJbL}sm7^iHlRCH90mvoE&Nd46qQBqbQzV?ob7TgsY^>FM*mU9AE~MzLugYWp!K zo~_d67262I z{u{#xmWT)^{ev(gENW5?AanO8~GyPro(h=thbk6Y??$O8(T> z=QADNPE2A6^``)W8)6Gn=@f)YcAP+&K`~?!?1_{~KVE&(;@w+$(yDDcaI0od)AjMc z{>a1w$SE_75EU(v z5R-FK*yJJw!6i=yX7f=GdYHg~u{18`LC}7<_E=a>?cRFawG(&!JP)Gmkpv9WR0cm6 zBdj7A9i%=kV98XpHArGlboMS)CmEFWnTR&4NdQ>k;ufAU#~RpB(rTsR`Ky6lHKfN- zFt25^0uJAbsKSm9b7)OTH4`D8p{g~^0**MtMil(UYkIC_ZH{Dxt)pX`EZe|NMulDC zUlC;xW#UV41LWN#y{LUA@1=4ClB+02re-PjBV8Ssfh=>a- zNyo#D>%7>o!pD{oAdyvk4OrSR;nERE5lIXh7a6Aw_12XVMG>G8#+D(h?g}iqv2I9+ zPN_W!PRueZ<1Qx4mW6IAt%g3HP_AMc9<0)J(s7B*whcLV2a<+~dzL2>oTKYn{4uEmWvSisCEjQ0H*w|~f(%`ioiO`E}5Z5NYCZYkpED*6* znv90ZNn!6B%*=`IP~8EJv&!FRZD*zl_P>zPg;NiG@>9|e{MARE`Rr%C;*YMr(esZVg!x-*zlSapwXO-5$`iMy=U|CkRMpZ0~ zb#n8oR9ps}n%+j|o{afd;mrXNk&|x3z(|?(mk`cCeZE&0Pkz)ojST{J7pn?n^6+1y8BMik&qbD(&Z+X;F7vACaJI*-!U2lKuo8I(hU1Co?ZO7r;j}Y2V zZ_3=vkSQga{XBf8uj#W|DBiY)#<& z%e?yW3uotKJ=%rDS+j@|PunH5)bb*845rYK?57}Jd<780$rdp~{SIOqt@Dwgqjfh# zvXh9uww5{+hWbUAVF|65jKn4-lCn`l3|N0xC2_LZ_XD3fxSBDYD)F7(VrN~VFv>tj z>0qRm(zSZ-5UcaEVrbQg3mA+Ho>4iC1CQud#=*+g%Wi+Anx{mG#9VZ~wnLy-7IyF5 zqnE3Q&`O=qs{}12o!H@p6AHK)E4n2Ik-Vo4fOGg0TUZVqykH;|8 zBvi#w>U`n%3oZ6JKXV&!)~T)<3DBt$k*1>3?i+_3Z@Mx?&Uph!O#`1D%7hp}mldjG z)UUQRp9q z>Aey~s&6*dKMUBaj{_ZW!U-pwbPg36wX9(CrO%2mDQ@49-_g(t@K2dT{p~ZRfr&MVqyqFV;(&BL27>?DF^s) zk&Pw?DGq5%TpdX0wqg-aGAW~#929nEA46pP@YG`Vocjr^NQXms&``1v-5=>$<%(l!K|2O)GW#_{ zW?u0%f(b(Od1eCigFq~x*i3wQhNZqf7+VX78X>Gnav&!%wor!ahpgUmBqE*l4uH{2-q$a zZ`q?pp*9coBd{iBL(?RHHF085Q`8zUo=c@iLo{agiEIhJ3@k95#cs;t0wZ&)Rb_<4 zeZ=mm(xXTUR(Wz>DR?OwSmNPv)m-2Nj+IrtTTC;mRrVnsF(PRU!6x=GCtOJU!#w32 zD0oh18j@YkY+NvUc9O2Ob=+Y)pjr;S%H%hNbz{Ht<~^@|?dyO2%BNoU_P71SPyXB^ zp77K=|KJZEc;GgDs9j%#i7S8iw*IwFPGDRV9SL#h5<>trmkOR>@#IQ}EJwV6e&!${ zBT9O_pzc0s-vfvld%qIF%{AC^BAep2PZr&1iAl~-;4T)a2Qh}}IN%bXU|%|taodg5 zHt;!EVVr`!p*FzpW$SK5Zwv6fgi>xla{GxpPXC@Cyvvur{N-z3_OdU0@e4an+i}8e zPSBrCi>Xij;%2j&1giudk0y>RP8z5nbBgm^0A9>Gw@@JWtwSb-`HG@V@a()ZK?{!n zJ`${VPo@fBGM6ec%?;xCuz^SPNGLW59@!$0GJJ-4FajLTj95J9R1&OJs!H3SZsTly zz2K#3XfqK{11cy`&U4g)7%xrDOr?PrdZ&@g;YD(ldYO+>36%wzh4zo=@-HvsLe2 z>fE8C16X+_Tyd-8`wtU40v|d$De*FbTynQ81S-3i)F&CjWA2_SmW0 zud;C!wy@*zIWrUJh-FILRIoT$mW~b$LaT(!uC?}^?TZXlpWW)JOiTU{VU~IH-&v9WWxX*)$ zWH9%MLgEBsy`jw$3nv*-PgzF8Y&oE0VV7;W!d=2)wt!Z86(KM!0E?gmRa|LqbOWt8 zYOE1cp)r-DOa|dGs`YcG;E}^xn@abs9`bfDuLf=U%2&Sn(wDvLDZlo_qYmHx3y*p7 z{U7*{L-gs|ZCiKk(Yxe(^C!N$cj+r4AoBYL@IlP`&nl|)AT}aF;!*X~usIw*mjuGd z)DfYyV<^*b`Cs1mOE%H0CvQxL6%2FbVo?XE-fT?SND@ z-l|NxKaZwmAUORCWPSgs-Y3!DD{kHNkDvdC*S`FktDpZ{lE3P;ul@0R-s|9l57t{c zxY3&%rgQ9$&D;yWJ+AjBBIGQh9C8(tX&g&TiCJelCQcetd)DhC5*8$EHcOkT+fk@Z zlrX1ES_uHghZ%n!U$oAf<&BT(&Rg|J5ov7EzxMAJ}QfJjwSA@=yD8Dw=at2#H2B=WtYcI}@~G&l%!? z-8=W_&Bkwi^M=>F;g28o&qBx53%GfM=o%M`Nz9=3xgrViI)uK}jQ?-Q!{|*1 z9C+ZGzSZrspSk{z{_uC-_9w47)yZe7v z4R;W)-yrKL0V@U1Kq41HLX|O0Kf*B~AneJNyXg(ZN{7K}312x;ld;`)cQP2~#c=KwrbXcK)nm6kGHJ!L05%939u})rX(YvXIQ@l$-mtSc$ROmH z`C*YIqy0(XM?#W0N3VPj3Zuf(QMaqK4Jf)=f=D|9 zvq6ry2lOWjC%yyh&~tttKX7tqpOG*gbEKHRQSC7j))lg zTatRUt}L@Vf{X~u7#C&4)GSM>7ojA=^Ggf_YaN4?5^+QX zgvsz_Qw=qZoB4VTt<6@Lcv7@`uRi_1Hw|+>6VT4hG z@Dt-bd-iQx+w!d&ZhZCYUjML%{DRi=k-vK7eShvDC!EOJXuJ39)<=H$*bldGdgJW? zeUOF!KF-2Z;m^kyKIP2;Nmp}|P)4Y99534@2b6b44w4EKj0q+3A>DgWMziO;ZU>VfJR zhha`Uo}v40N>VALJUFljhre0t>98|{%ACwPWs7XP_%E0QOK-KWESNQfFu7wy2lVaJ zimxVSQqRG6oF2o0OY$W$aQDsRgOQ*R`eJPs3fU~qI0osf`U|9Px8rTbCAO-}=G32^;SIGf!eor@2j1O`k+v}0L$h=mpw<|*Eh>JbCulmtL(a|MNw!{qH;A zZ$JL2r#|&5uYCD6XP%WJaqKo-)z*4fX7VscDW39X z43hkoWtt+@zz=pln^%@0W)gCh1Q8fh%s?alU``41#}WFV)aK2*ck$ZVA%`Av=Go_+ zdCmpze(USs@cK7w+Pd`)x4YeeTes{Ksj9Ghpa^`ywE|@z4nkci zEg&=?J;f-jwQ#WmG<(C&52nkcjsmMLcwp?Hqp--`@~=JNOAkNt z$Xn=({`c`$0feSXuV45K#wNx#+cL~h4&QbocL<%2&tC@ABvd4%X)+xX(F?>5ET#URVieg z$i}Li59K-^$nz`#$)QQ+Awk#_6Z= zMoWq(k>FT|WXz}w&L~7pmiR7|XWQo`sig#%G(E7|CT4~RTa$r|L$$TF+`|z-9sro0 z*ahyFOi=4r8bUG3)HXuJ$-wg)8gMGGb(#Cf?1d(`I6aO6#+a8`))Svjyh3mwcCenk zy{eTe+R;gxaQQ?nxf63nJ&?>(HrtMnF`dJ+d63d9ev;-COB}WFP!w@!E1Dkouo;6! z+H_?AsSEDAFF|!{MrX}X1|k)YkVNM}B#SSNTka#l8YCR2!+NE&h{yi{s6hJYo+x3O zCwGNuKTfnE%CX#(rzu+N*!+!J_@ok^!=eLB$H#@KG#)xQ@i1`@s$5;;%0Yk>5EG>3 zKSKjh`M3Cn8_8{Gm!3m_S`x0cW z+3BqmD59a49|Y1HEP5_*z?QAs z&OGPrQ_no_KmPsSUh|5Ve&bs=U2y(+M;vhkM>JE+69;%@%$%92ni2_E9sqeNYOV`x z=Y$JGE@O@eKB)bxS{_ISc$M^FB?gLH`2a4ljiXVG6o56!JDU;i1qxX#;a7h0T5|@> zT5}CzU^VC#K_Mp?-d!LH08r+xb>SLBu^Ds&rOvwi98{RoO`>g)a4M=6ZfFxsiANB& z^3fU52ueUj5$e%aVazbk!50 z4|yvc1-fu)sM1!vS^#I3j5a~mJz{}lz4^u)Zu+g?`~54PeEEsT9{k8>yx{Klx!++2 zAG~|_F1_-wrq`l%#LUNv$#N&;h(*#Ze91yF5ld!7V1q=%ZGH#It~bUKg;aBsP&I~* zl6E9dUM4PxIpRrj`By(f8wxczJRK&)bHve0Xd9D-28S%}3g2udOHQKZ6NpDR-GR?S z9kO&a32L0HGv_%KXDsfXuY1L-Uv=$y=U#BuS!d}v04X{I z+i6f+x?BYbQ#)ZYh*AhE$(Vnu{vsu+QgWc2WWJN-@3HO znKc_NpdtZW!tgC_)`iJ%GH={^)G8=8(+mx>?tF*V5!aFE6ok#IW*D)pMDGp3OMk5F zs`I9vqwYTQv4piQi8gc_Qq_6_aAh>iC1)bYOgN^lwkKjXaobvNwBalK3?v=*Rx(@B z$4yxye(TznkAC#yzj)ct>r1uIx$t`)`J`u_f8p))%8*`W(;tTEJ9osAdvcjjcwb#U z_#*^+R$a4%V@0E}7f@O&)H>)26M!TgG!PHSE{v^mD_zku38TM)fglgWnlw^|j)|+T z`YyDk>aj7%8#9p!>%gqFEq4ulA1iGKr+K1O2FySS{Ko)#BBjgb<^yhh!bzu|dE3u^ z;^Tk%);E6rh8ypA`#ap?h{N^tKrCE$WuzZldO-YH?TQ&yrDjx)@lMv}jv_E_Y{chu z4Ue%`v38N14b5U{*^o2uE``N@BudKGFH9p=fI)`Aa}~HI$lGP{)DziJ5G%i`W1Sc} z+_E?=zML5%09_FbQVjT!&iz=pNxa_DzS4`Oh4MUh9mAi^qlCl70 z2C=tSt(j57Z91KCD5y&^;>%o2GhmuI3{2Juof9^L%@8iFNU~_dMRXdPh=agp@!>VM z5oa06dI@~@4_}l)7eg{Oc=w*Y`q$bw+<5bA-tdOU|H`A}>sNl`5AJr)pE~03?fTe{ z&TaaeV4iR4CbdpU6^{Jqr@i&W*p2dvyBc{eowHLw%6k?hNI&br>CB9g^8z_a13Xpg z3GWQtwex^7Z!i%R&M`B)2HZfWlmZPgGXHrl4O|9kY^^SFacW7Z2(00r$NkXOsVL?q zfZaAj6*0A3=v4|)=ShR6R5P(>ldcQu=zYvX4>{zt+n#;sVMl)Oz3;jHv!6Ns_!G`N z;|!h4c>Bcps3kvUM~x%$bZdlQJc0vBqMloA1>Yzn4GbC|iJ+3u*RTJA8OwmIas&l| zSOpTX7gx2|z+=6q5kdb}7wzoV`u1J~G?Z?oHn)W~j>hSMs-g8OhL#vGd=5~XMNlj- zB?Wafz|2{WU}`v759;Eu`fsHZ|V+pl4Gua1a@VSMziSEtHoca z(FUQ(ahK7OP;}8CT_(a#BobIsTlkb>d6P~9aSYn9mhCdRC8pWvhpk`=YvUCOVaqX* zZ~*2kRB|=(8RqokPkkQ4j}h2A7cPYGy0(w#5w44E!VHb0Sq0kO=EOFNth*#Za6_12 zB*F>7bx7VrF_bJ1LZ_rIEaQ=5=~iIE1%Nb~kr8bBEkZaVYHvnd^p8DamO~|T!Ff-9 zgy&) z16;o~IT->dzZIP0As`2pAWBvFGV*oYls@1@mK93gxMVy?;-Zr7c{8ih3ewADGMNdF zbVRlqV@<@+G9Bbs{GK_pN>;@I)?9a}p%1n6Gd6RCD8#U==qK6{Mr4ZH$c|pY#?lj8 zc11TR5sPOoHjDS!L&$T_6$?p7w(;T+?M$X&B%_}F(C=6mxu7ehlR!uxrv}Wx!~kNF z()ExmWF^}rIH(~Bu8>p8jM51>i^=TB2SebU1a+APH;0R!r zpH@w+x4x}?@EYP{SCKem!Upf?EYUy`$IC4#U)B$RO23MWb7#4Y%;#h;Gq0uyD?DaCy z!E0;hUU>U6Z+qT5|Kv4S|IsxkoqEaz=bX-qwTw(Wp{TMlAHommD#j*nO zHW3XM2}CJiWzAYkC>uOE{ul}+CR0F2Lg)df#E%myC5uK$xB%&K-6|K>4g!y;N40|S)%mGL>M=8OqU(at!3qv{E zPKK;W$CgE&fp%LYYHGbqol2A7z$Q_~M!Rbdz;H8swSmc{RY<6Tsfm;>^vh`7005#H z5Rq$dKg`Q{acw}`i!AC10I=Av)Z#(xXVm-C7g#C**8|p%1r87}maBk`A*|}#Vxttz zYB44=Kv*l(8YAISeHuMXoNh2>9?`HO2J-X~!Nh2^?ih}FY8}Z7Pj}VA;m0~z$gPv! z#y*g^uTGZCHUz%%WZtb?t(Xrhb1u?L`mxm?vNQi;p_~ z_!IRG``*2~)_jJxb1hlfs;$gOI#WhSzQB1Nf+awJoLe2F8ozqOD8(mxE-y86lCqM< z8{tfm#!V@Po{l|I+b$~i!>otY9Hbw~=M#&JdMm=WYMV@&3x3_TxI$-78GX@Bg2;&MY018h%|Wp!oX zP@AoM+0>rw)igi~UQRuh2(How(+Y<%SNIB6HB*Svl~L&}V>`E|GIJIP*xd|rH!*X# zUlidV5~qP#R#Y^`sfr`BmrWp26&3Ax5P{_@5~Pi{cHx~gbTbWuVoB4uQMHQzEsiK| z2ab;J^tFSWf#40JP2b=oxFHdztcug3jtqDX*tBcs-q*bLb&q|_gZ0H@zxJHx-{tQ2 zJaFsQn|I!<7cREygX;VtiQa?My&>-Osl-l}Fzk#@hfeDTO+a2)eb5|KL)Y{SK{1`%zn;a`<%IBY_QUOggh_@aoaW&#wdDt(%= zv|b|$o?1UtaPs_yk1vAZbDx_JIQZZLPdsJEk;mTZ{qK0|AHVU9ce><~9Xn3Z*-Q_n zowT{(i6e8-&Ez@AEDizrCqUIPiQFe3p;<|p(qh|?$+E=8V6bq?q|TdAgDV%HD3aF0 z=}IlUISegt!4`g%0jFKolegSHJOCXF$I^hAq-DWNvq6b~K+*Wo?SdulM5B)3RNY6( zak}6QTB%y8`71lE0Y_$xkdZ=96;g>dl$LedEZgkAMiIi93SH zV1uqP-)%c_O_5?9YJCLgX_?RcF$zO~%i&gr3zn%%CX=Ui2}M)-fM7#Hx= z%h_oNGLIg*%b`GQJp4P5!%sA0Xh1ea$>s^GqkclCi-D#`t~`si%O+Tk-1hFXOz%EU z3YrdsJJvC53u&j^YA__xHg-b``y7h^o)w?))$1~L0HTP|uGnTaR_1acXreN=6N1bt z#8c3jFy}Ejz?p}M%ui!wKk~F&2y|_A4tjr?8yC&DUf21XkA3X1zw+o$fBfV3zTX2M z^vKKgPanAgZ`!*}b#8CGE=)$dhlQZShSbH=&nrR5H7f=TT}*07gO^%zCf3Ea=~4^O zmy-YrX6C`){>zSu&*T%cgBgsoeH@_oZ<x_8qpk2(5`Gtd6om;dFpuYUQLzWlYj+~qFY4?RRkrjNjI?wzhK)~=8< zd8O4*1+=Th&JIH)%i0#G9Ux#EnMTIt650G~jVc%WkD;c>qHvfKEm1bsp=8iPyoev5 zwG1kqn&_wvGaoRMmOBkyBx98->d?3@{rblAZCnhESrJQ^ai!vcDjwBfM-FALmf$3a z#IxVIfl_nvn@^dXlWdC<+j zde!sqaqs);s|ff&`d)npF)yj<)WskA`d`!fV6jIyv#-ox<9@C)1Nx|C(M;qLm%C?M%n6BI0? zSB81gC%CgHdh87yZ20uR)o?#LO-p2>Slblsy0ww-M~jujL!j!9pq$|x(jt(LZ9C?#0fkrZg z*I|cqD4IJ-l~sEg*&1GRI(*p_Xr{l7toLsBRKelR?=!U*$~Gtq1wvMVgT|dCc}v=8 z+YzITYB7{J*AAKL`l=Un^z|Aa{Ln`p@yn0+j~HqM;v+K9q+Vj=g!w%`%--(>vk7hbl9PX^3*GzuH}-(+zc9fQDuJU zql$!@DJ#8g*)VVOF412$9vN<2D1GN_1qIN7#-5_MM*EUOYK2Zb=h z7&DxG)>tAY28|mADlt~=1CG|>Zo2hEhoP)WqLJxhrG7@!OqRwCfF*rpqM1mV zWaZ2-r+5I54X4pEHj@#86H>u_jNv5@q@^)<=_iaRBQ4;Bqw9PNVAV?Hp|Pon z-AZC;r@=U_5d!1@D|oECL~QdGt#4tc$UI%wB~`=Bpf+fI)tdM*5Qv5@nCq7{S}ChT zMuDw>xT?7{8v{?|cc9bSiAs#Mi1Z8>TlI05Vu9rvlfsbeM9>jMILA<^sS$QEUlg(( zhSg8Qq`Eg7N-z~T6M6!x=?Dn3WH?!j?nD$T34H!yA&PT+3lLT|n5>Fv$*E^AiXcVg zNWv!QdW}Ny9ZCSY4zjQ`?`#$9SNvF@mdF|J9%yCL(t+9KSN7UF z13=gad$tKW^#z_wvDf4RRX4&JHq6Fi3+BZwY-raRYM8YYmHO6FxihtrIJOC~VW`?b4}U-|`%Ewu6Xl&N&)pJ?zjOk!5yx zD_+kmaEU$;8X=59;gAVM(u9vano&4w=o?0BoL05aqpz-yLpKft8IA^&QJ}9N%w~UXQj5R6!;_S47*l~Bo9LO>PM>(I=cnqxl&e`L_5HQ zT(b+H3YVxcu&g4cSyi-2Gq>S>P>A%~e$@4&2(w&HR+4d%9FYtdhkzccyajYR@fjZ> zPZrEjjqm01w;j^E617r|%-uNrq3?_}n22*(*Pr zicGENs{JA_mv){QD!c+ABRq5Em5Rc4tO*Y$=3PYr7~hHG9|i#G@L1NY*QItcx&V#F z%90kcS{A0wIxn)QCy=rB-iu+d?3%~RlK31a-2}|!d&V5I@S01#eq*0`Cj+%g-3#c+ z*%rCxO#yYc9em(PJ9gZ(Yv0HJ`Y-aK#`zR?d&n8IFyR54qBg7!s?4RL7X@8L>q?}PV(PAg zCVXU>0dZBPZp>SD)UuR5UmbQqp<~A5|m6NSm@MOcICPtX@IRSy+i{~ zX9I9(r5SzU+K+l7au_C5FC2&~Hf!y^C8d(AVZoTlR;(N+gpw=<6-2E($HP)QwHdC+ z7eu>O&(622->;Ao^Q?h@&x;S^Py&{E4tMEi-6w=peuRIf z-G9IF@zN{e_3}Vg6~NRX9JCngH+3_4jHsRiMh}i`4R14z^EXjo))$Z%wR>)yB5GuF z8Q0N9iD5fazmNzuW9$q>Zo@eMHrJ@OP2|IKIGeeQK(DxnI~m1~^zvk9ZNak5Htn_a zjtR30&QXteW#}R;KAefKHJrG7JDbVI+Sg{8b1LToieG(t_8;vFFNH$SnRrhWeCbCxt<09jdxXO z9qO7BOO~89WLJS^`s~G_m|H#Ywjsm}_UUq~r(yEEwt34fZgI=A&OPt5pZdfrUvbSr z2OoCH#TRc~TPvHymtc~b`KXv`oO$}~J~rOqogbESadZ-h%RyD#=|`l#SwW~6iIaBG z;->N($|B*VvyLMsArVd(mEcQ7Hj-0w$g2RVU*^!>VrX@dbQ4*bjKR{evt<}+kHcBa zj%_v3k>+GAgoBio9*&MGOjXH3;lpt+fs!8nbG;Xj& z^YMr{nYQ1-7o_!BEFnn8DP^N*M6NPne(0G+i3yhTsIDD+c2O4x|4+z$TeqxTaJvh4 z?b-B}*T3o;H{5vMdFS8qmi!4*EHllRJ4#v>SYqDOOv)N~QY`l*XC`goa066LAikRz zpYl}YSh0<5v*LhLBJ9z3Y{}3>MpZZVgQYue zYv3*9OcYV&L0*24e59bijR!IzUuso0q_?gFBjL!p05(g%Nmfmpu^f4}D>D1*g?-#Qrq&J$6}H&;0Ub9H8}6(SXR%p0(TDMmYK%tB_SjrvwEyq{GAz(n{?g=*j$f9K^5@1c@;-DRwVTCkw_FQw1 z=c2?*IN`1z3m8j@Hgp(~QSE}kVVvn;1(bU6Vx^9iMFNsydO9tjzo9HjLYa$q-4IB* zs`vDwmgk|IAqf4Xa0uN&Y^ysihdr9{xo}_BPai! zRo1Ci%UZcLeIXshVpx$Ud>~DuE|yt(8a`*D&&BD_V1EDie(#!>yzoH}d)xya{HR;q z>e!t(-^6SGUPT$~J%E3)hoydpBMqh^vErq~anKsXWemBQWLXU2r4eEqfpTMknHmYv zx{y1P%tBbi8TENvUW&Gt%hwBxgjI3DO&rH2!4gwzY$fKk4Lu{o0rR_|?}Qa@e7_yXf|Z z9CEOLUL#P>mU*Qx@T@0Z+(oz~rmPbn5cRMGL>NYi(SQu>0tiVlz>SJ*?K@ptTiE&m zN=M>YC-oJS5&NkEntbjD^X)|&?BrQ85(x2Jn`RNDw~ia*PH`azs$Wls0jji5wLxpt z&~8iI>b6N6DP&oWn)IPuH+zBm0v>;rBY1ZOV7u8~b%+^T0t6(PU6Q}jI-AN`O!*z61E`I3e@ zvKGg20bK(0J)W1&q~4oTyfT!s)6NZPIUh``;}Y8>p*m6mbcc#a<=^LNb$syY3{rk& zTHOwWwpi#9yp1@)xirwIh?ZJ@oo+tXT~K*lVFk0eaJR|Jhe6n z+lK~j66E259KmwNUa*aU0 zC_Gmn`L~<;)4Bt;>Ma2M(Z!|%&OGa!pZ&#$pLoJ4&wS=H|Lnc*#YWWj?%X9nmWue) z^~^8@t=_=%q&5Jer0)O- zjfe=1IwdN1s;ENN-%$6EC?HG3FWwhjY6Zy>2FTUb=br zrWe2XMZf+3KJWYs&cEL;JoLC@kMTbs-=ou;{$xoHeJ`0eh7P%kN1nse{P@>djv*cu z3_VBZWhu07(owT4G%AL5lDx{CDO2`|9=#qsF~ubr^lX^|I5($G4;`c~7SUr8O1v}! zCt6?KVx$_dv~e8sfbnN0ubpK=4kDm(mDKCL*h(|yz)hlyNtT4`llHo5pt`uQ%-;WI z(`047WhVnZAG&Anrqj+m{fF*;Z#jMLv!3;qx4n&jDzh87V&JSyu%s~_jQuwV;zEfl z;E1_!_)N~wit3=0fV^Nr=aOmgBFRP3#ngwbp=4q!6tV0&Q4KmG$k6~Q9P6U;i`3jK50i)l@Z14TZxR_((8c{T8$80gE z0$mCQHL}Ud`mhBn%Eqf*s0YPDf|f5UKvgqJEFPDiSfMX@x6x}PRUIW`)iYt%h0H9n zh{z*Vf>j1;+Qt`iph~CVYMoq-B_~>p&>%I!k`*6usanz`=sxjIlkPnx|I%^!cVLb& z0Z34et;Cf@!)NCm4_HREv}SW~ zSy}kfBz={Rr^i!U3+UA;v372k~ zs7vU+n{V3r@@rr5@P|I+!rNW+pMU+gF23Y@^y0JNMD79w1UBQf0-yHHpl1jWCVA)T z0WK_-qBkYx_(g}100MI@2}6F1!ZGW8{-U)V*1f6Xz_qU`GOZ#6=Q%u!#CVAL_-ELi zosw*7o5G~u*cDTUOjwy|poW7m++&I45}4)g1eV(KCqNV845SJtWy0mtRRH#E(Vfjf z2W{T7Q|A&s+n^@{e}3I{k9g3366n3}`{4I~-zBibH;(&=fZ+fDKmbWZK~$PZA~ND& zMC^{$ej@1IBYs|v)J2^DYBr#f0he!2k)vcP_?1SMs*`~vxlxiv1wfhiXl2+QJbMEX zJIBbRb_Xs3iD#cu%pW_V^%Og@crF8)ISdFO+HZ-2R;`XKjp6JWu{mSas#OIsk76X~Q)5Ts#%+c2)?deTf?A*Rq4g&k`+7Xm2+{^Sb)y9N|-Vx`IW`21y!p*tFum?_YY&wfDT&J=XMRWSnAzg$n43E`vwGutDt;y(i7> z#L!mA#bZs>1!{nXDkC5|Jq20K04>jkw7_N)U=Re}^$-u=(ny$+Y3662RO%3gJXf7$-oK;-&sSZjtfMa@@n= z2bDZ{8hkhz;F~iU-~)sLR6~uVnG1l##p*EI(Ac3fSx1~f5>SAeAAys-XGtuXEzE0! z)Z7rR=F%Y%)|M@s^zDXvrlq@o{Z9sceCJlTKK`gU=xj)D+?{4FFS7jMc|iQ^(N-ueDq^az2eFL=gVJy#8aR9LwCD}{@i!huAB7- zGP2XxP-5*Fx5I@jM;!EZh~t3?my38LMQG4UibBSlh2t3&QEbwTl0E^*a3bo-$voP6qm2Oj*6H@)Geoi|;4$BU0V@<{yq z4>ZFqDit`rNl4jShK`CCI>!lKRqWdlxS#VIyDnJl7S_!F7^h>4Asb%mdOcaU z3T)xAT|8D-YEN@8E6hD`8^e(4M4%y+4-}_Ui#ny&+p1||u}D|t9V93;I*|>R$Smv) zv6wEH;hES5fH*xsZC*kiYInf|RY;GWqXdg~p&iKVrPi{iDjbgu$Iy-(NNALaUj5d8dDq|2{p}~Nf8vua|GUpz|M1J7anJi+ zdhoVw`eto?xt_igNK-7lE*1LWvW&ybS5E)DG|Z&r8W@+pOo8_q)dUy{re6o-V0g8g zk$-I|6vOzW$HxGEK!Lv!?MFba1@VnlM_~&mEqKU?&ybo6_iIw7O;qvNC!yj_GCkxm z9h1|aIvKeh3aO_)T@U4q$@4^*(O%RGShbEA9CHBqEdWm~;j8c>AFsy)<7-YfZC=~D z^`sp;Hg8^g`AhzA`;kXoe8)R%+qR~6Zgn2bD7v&dZpv^aRh7<(JGd z2R#o05W9;b8iR<88`CNNi0!WiY9tTKbb%j8X|lX^nXg4a-*&_ex07-&)<&cYgr2J* zN+;3~v_x&~yGgQio!2sS{FyqFMO~osOK>Y@aackb*R7XuWkImA$mGK=f!BU^yvo@c zGi0DHBYy2ZV^388Y(TVA0XRf9sAZqr6HgaG%w1zlZ7z}=b>@h+>?|?J5aIppKE{ko zM6eBI_o`q7F-1>+xBT;$zIxSFzwz#Oz2kw8z2e?K{qu(&a@ZbyA@1JYIUGbmXfjfo z!`vN08^vdih|O+4lmD6!&6|z}y*^zNXkMAEP~nY}p`Qw7TW|&jraDT$YNGw#r$mAT z;gV^~xlA^dcx&g@i^q%Q5H|sB_!Oz0mWNpZp#V7ajG4;FYLwIpXX`N!hR3>Qul>Xa z4En96Prnkuu(`ek0%nyhdR0lwryHTQwaurVe%jan_t#(ls#n~+bI;v>^locg*YdKy z_ofZPYAT-n;fNoFp&2HL*)wCkEM>I%z^$gQ9zo}QCohwf$

Q6n@N9JcxY+?svC9 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 diff --git a/skills/harness/harness-init/assets/AGENTS.md.template b/skills/harness/harness-init/assets/AGENTS.md.template index 6a1b3da..ceb4cdc 100644 --- a/skills/harness/harness-init/assets/AGENTS.md.template +++ b/skills/harness/harness-init/assets/AGENTS.md.template @@ -76,7 +76,7 @@ leaves the next invocation a clean re-derivation from disk. Four layers gate "done." All four must pass; none can be talked past. 1. **Pre-commit hooks** — linters, formatters, type checks ([PROJECT CONFIG]). -2. **Slice signals** — each slice's `Signal` section runs during `/implement-slice`. +2. **Slice unit tests** — each slice's tests run during `/implement-slice`. 3. **CI** — full test suite, full type check, full lint (incl. custom invariant lints in `scripts/lints/`). 4. **PRD runner** — `./prds//run-prd-test.sh` must exit 0 before merge. This is the definition of done. diff --git a/skills/sdd/implement-mainspec/references/subagent-prompt-template.md b/skills/sdd/implement-mainspec/references/subagent-prompt-template.md index 3228f60..255f808 100644 --- a/skills/sdd/implement-mainspec/references/subagent-prompt-template.md +++ b/skills/sdd/implement-mainspec/references/subagent-prompt-template.md @@ -15,18 +15,11 @@ Read the slice file at: (This is an absolute path — it may be outside your working directory) -Configuration: - max_signal_iterations: 3 - (Cap on the inner signal-fix-retry loop in implement-slice. If signal validation - has not passed after 3 fix attempts, return FAILURE with reason: signal_failure - and the last signal output. Do not loop indefinitely.) - Follow the implement-slice workflow (preloaded in your context) to implement the slice. Report your result: - SUCCESS: all code implemented, tests pass. List key files created/modified. - - FAILURE: describe what went wrong and where you stopped. If signal-related, - include reason: signal_failure and the last signal output. + - FAILURE: describe what went wrong and where you stopped. Do NOT use AskUserQuestion — no human is in the loop. Do NOT run any git commands (add, commit, push) — the orchestrator handles git. diff --git a/skills/sdd/implement-slice/SKILL.md b/skills/sdd/implement-slice/SKILL.md index 5d0071e..045e5fe 100644 --- a/skills/sdd/implement-slice/SKILL.md +++ b/skills/sdd/implement-slice/SKILL.md @@ -1,11 +1,11 @@ --- name: implement-slice -description: Implements a single slice with Signal validation and unit tests. Agent-first — invoked by the slice-implementer subagent (under implement-mainspec). No human-in-the-loop; signal validation iterates up to a bounded `max_signal_iterations` (default 3) before reporting FAILURE. +description: Implements a single slice with unit tests and a Reflect step. Agent-first — invoked by the slice-implementer subagent (under implement-mainspec). No human-in-the-loop. --- # Implement Slice -Executes a single slice with Signal validation and unit tests. Agent-first: invoked by the `slice-implementer` subagent in a worktree the parent orchestrator (`implement-mainspec`) has set up. No human prompts; bounded inner loop. +Executes a single slice with unit tests and a post-implementation Reflect step. Agent-first: invoked by the `slice-implementer` subagent under the parent orchestrator (`implement-mainspec`). No human prompts. ## Invocation Contract @@ -13,72 +13,78 @@ This skill is invoked by the `slice-implementer` subagent, not directly by the h **Inputs:** - `slice_path` — absolute path to the slice file (may be outside the working directory). -- `working_directory` — absolute path to the worktree where work happens. -- `max_signal_iterations` — cap on the inner signal-fix-retry loop. Default: 3. +- `working_directory` — absolute path to the feature branch checkout (repo root). **Outputs (uncommitted, in the working directory):** - Implemented code matching the slice's specification. -- Signal validation completed (passed or skipped per the slice's Signal section). - Unit tests created/updated. +- Optional: edits under `.claude/skills/expert/references/` if Reflect produced a high-bar update. The parent orchestrator (`implement-mainspec`) handles git (add, commit, push) after this skill exits. Do NOT commit, do NOT run git operations, do NOT create PRs. **Result reporting (to the calling subagent):** -- **SUCCESS**: list key files changed, signal status (passed | skipped), tests passing. -- **FAILURE**: describe what went wrong. Reasons include: `signal_failure` (cap hit), `test_failure` (unit tests red), `implementation_blocked` (spec contradicts the codebase). +- **SUCCESS**: list key files changed, tests passing, Reflect outcome (no-op | add | edit | delete). +- **FAILURE**: describe what went wrong. Reasons include: `test_failure` (unit tests red), `implementation_blocked` (spec contradicts the codebase). ## Workflow 1. **Read slice** - Load the entire slice file into context. 2. **Create TODO list** - Three items: - `{slice-name} - Implement` - - `{slice-name} - Signal Validation` - `{slice-name} - Unit Tests` + - `{slice-name} - Reflect` 3. **Implement** - Mark in_progress, implement all code specified in the slice. -4. **Signal validation** - Check the Signal section: - - If Signal Skill specified: invoke `skill: "[signal-name]"`, wait for output. - - Compare against Expected Behavior. - - Fix issues and re-invoke. Track iterations. - - If iterations reach `max_signal_iterations` (default 3) without success, return FAILURE with `reason: signal_failure` and the last signal output. Do not loop indefinitely. - - If Signal Skill is "None": skip to unit tests. -5. **Unit tests** - Create/update unit tests for the implemented functionality. +4. **Unit tests** - Create/update unit tests for the implemented functionality. All tests must pass before proceeding. +5. **Reflect** - See the Reflection Protocol below. 6. **Complete** - Mark all TODOs complete, stop. -The working directory is set up freshly by `implement-mainspec` (a per-slice git worktree branched from `feature/`). There should be no prior partial state to resume from — work as if the slate is clean. +The working directory is the feature branch checkout. There should be no prior partial state to resume from — work as if the slate is clean. -## Signal Processing +## Reflection Protocol -Each slice includes a Signal section after the Objective: +Run only after Implement + Unit Tests are green. -```markdown -## Signal +### Step A — Load long-term memory -**Signal Skill:** [signal-skill-name | None] +Invoke `/expert` so the skill body and its reference files are pulled into your context: -**Expected Behavior:** -- What should succeed when correctly implemented ``` +skill: "expert" +``` +If absent, Reflect is a no-op. Never fail the slice on missing `/expert`. + +Otherwise, read the reference files that overlap with what this slice touched (architecture area, patterns used, file types modified). + +### Step B — Judge: add, edit, delete, or no-op + +You now hold two things: +1. **Your experience implementing this slice** — what was confusing, what pattern you implemented, where the spec contradicted the actual codebase (already in your context window). +2. **The current long-term memory** — what `/expert` says about those areas (loaded in Step A). + +High bar — default to **no-op** unless you have a strong reason to add, edit, or delete. Use the following table to guide your decision: + +| Outcome | When to use | +|---------|------------| +| **NO-OP** (default) | Routine work, small adjustments, no contradiction. Prefer this. | +| **ADD** | A new fact, few-shot example, or procedure the project lacks. Use reference-file prefixes: `how-to-*` / `concept-*` / `pattern-*` / `invariant-*` / `example-*`. | +| **EDIT** | An existing reference is partially wrong; correct it in place. | +| **DELETE** | An existing reference contradicts merged code reality. | + +Strong signals to act: slice got stuck for many iterations, or the slice spec explicitly contradicted code that already exists. Small deviations are noise — prefer NO-OP. -### Signal Workflow +### Step C — Apply directly (only for add/edit/delete) -1. After implementing slice code, check the Signal section -2. If Signal Skill is specified: - - Invoke the signal: `skill: "[signal-name]"` - - Wait for signal output - - Follow the guidance from Signal -3. If signal indicates success: Continue to unit tests -4. If signal indicates failure: - - Review signal output to identify specific issue - - Fix the implementation - - Re-invoke signal until success -5. If Signal Skill is "None": Skip to unit tests +- Write the change to `.claude/skills/expert/references/`. +- If you added or deleted a reference file, update `.claude/skills/expert/SKILL.md`'s one-line index. +- Do NOT touch `AGENTS.md` — that is owned by `/learn` post-merge. +- The orchestrator commits these Expert-file changes with the slice and has full authority to resolve any resulting merge conflicts. ## TODO Structure ``` [ ] 1.3-user-auth - Implement -[ ] 1.3-user-auth - Signal Validation [ ] 1.3-user-auth - Unit Tests +[ ] 1.3-user-auth - Reflect ``` ## Guidelines @@ -86,7 +92,7 @@ Each slice includes a Signal section after the Objective: **DON'T:** - Use `AskUserQuestion`. No human is in the loop. - Implement beyond the slice scope. -- Proceed with failing signal validation — but also do not exceed `max_signal_iterations`; if the cap is hit, return FAILURE with `reason: signal_failure` and the last signal output. -- Skip signal validation if specified. +- Proceed with failing unit tests. - Implement dependent slices (that's for implement-mainspec). -- Run git commands or create PRs — the parent orchestrator handles git. \ No newline at end of file +- Run git commands or create PRs — the parent orchestrator handles git. +- Fail the slice because `/expert` is unavailable or Reflect produced no update. diff --git a/skills/sdd/spec-planning/SKILL.md b/skills/sdd/spec-planning/SKILL.md index 5c4eab2..079927d 100644 --- a/skills/sdd/spec-planning/SKILL.md +++ b/skills/sdd/spec-planning/SKILL.md @@ -48,13 +48,14 @@ Spec planning starts with the end in mind. You create a mainspec that defines th - **Ground entirely in the PRD and codebase** — Operate from `prds//prd.md` and the codebase. Do NOT use AskUserQuestion. There is no human in the loop. If the PRD is too ambiguous to ground (contradictions, undefined terms, missing definition of done), follow the Ambiguous PRD handling protocol in the Invocation Contract above. - **Research codebase first** - Verify what exists today before planning. Look at specs folder to see what's been done, but verify against actual code since specs may be outdated. - **Reference the real codebase** - Ground specs in reality with actual file paths, existing patterns, and current implementations. Show what exists today as context for what should exist tomorrow. -- **Encode the PRD test as a slice success criterion** — The PRD's `run-prd-test.sh` is the definition of done. The mainspec must include a slice (typically the final one) whose Signal section names the PRD test runner (`./prds//run-prd-test.sh`) as the validation command. When this slice completes, `./prds//run-prd-test.sh` must exit 0. Document this requirement explicitly in the slice's Objective so the implementing agent does not miss it. The runner is intentionally opaque to spec-planning: it may invoke a unit test, an LLM-as-judge prompt, deterministic shell checks, or any mix — the slice's job is to make it pass, not to assume its internals. +- **Encode the PRD test as the final slice's Success Criteria** — The PRD's `run-prd-test.sh` is the definition of done. The mainspec must include a final slice whose `## Success Criteria` section names the PRD test runner (`./prds//run-prd-test.sh`) and requires it to exit 0. Document this requirement explicitly in the slice's Objective so the implementing agent does not miss it. The runner is intentionally opaque to spec-planning: it may invoke a unit test, an LLM-as-judge prompt, deterministic shell checks, or any mix — the slice's job is to make it pass, not to assume its internals. - **Think temporally** - Order mainspecs (which feature comes first?) and slices (which slice enables the next?). Document dependencies clearly. - **Right level of detail** - Clear enough for implementation agents to understand intent, but not so detailed you make up features or constrain solutions unnecessarily. - **Document forward requirements** - In each slice, capture what future slices will need from the current work. Prevents rework and enables temporal planning. - **Focus on WHAT not HOW** - Specs define intent and outcomes, not implementation steps. Use code snippets, exact file paths, and examples for context (see Context Engineering below), but don't write full implementation plans. Paint the picture of WHAT needs to exist and WHY, leaving HOW to the implementation phase. -- **Auto-invoke experts when triggers match** - Read the experts catalog at start of planning and invoke relevant experts to curate domain-specific context. -- **Write Signal section into every slice** - Every slice must include a Signal section to indicate how to validate the implementation. If no Signal matches, mark as None. +- **Consult experts** — Two tiers complement each other: + - **`/expert`** (project's long-term memory) — invoke on any non-trivial slice, design question, or architecture decision. Gives you what the project already knows about its own codebase: patterns, invariants, lessons from past slices. + - **`/expert-*`** (outside experts) — invoke when a slice touches a shared library, internal platform, or vendor SDK for which an outside expert exists. Read `references/experts.md` to discover what outside experts are available. - **Write Slice Dependency Map into every mainspec** - Every mainspec must include a "Slice Dependency Map" section with a `Slice | Depends On | Blocks` table and a Mermaid flowchart visualizing the DAG. This is the single source of truth for slice dependencies. ## Output Structure @@ -279,61 +280,34 @@ backend/ - Workspace-specific package.json: Email dependencies isolated from main backend ``` -## Expert & Signal Integration +## Expert Integration -Experts and Signals enhance spec planning by curating domain knowledge (Experts) and defining runtime validation (Signals). +Experts give planning the right domain context before slice content is written. Two tiers: -### What Are Experts? +### `/expert` — Project long-term memory -Experts are Agent Skills that provide domain-specific guidance during spec planning. They help curate better context by offering framework-specific patterns, security best practices, and internal library documentation, etc. +The project's own accumulated knowledge: architecture patterns, invariants, lessons from past slices, naming conventions, where things live. If present, consult it on any non-trivial design or architecture question. -**MUST Read the experts catalog at START of planning:** `references/experts.md` +**MUST consult at start of planning (if available):** `skill: "expert"` -### What Are Signals? +Read the skill body + relevant reference files. Use what you learn to: +- Avoid repeating patterns the project has already encoded +- Ground BEFORE/AFTER examples in real file paths and current patterns +- Avoid contradicting known invariants -Signals are Agent Skills that provide runtime feedback during implementation. They validate that code works as expected beyond just unit tests passing. +### `/expert-*` — Outside experts -**MUST Read the signals catalog at START of planning:** `references/signals.md` +Domain knowledge for shared libraries, internal platforms, and vendor SDKs the project depends on. Not project knowledge — but the project's slices may rely on these. -### How to Use Experts During Planning +**Read the catalog at start of planning:** `references/experts.md` - this is your inventory for outside experts. -1. Read `references/experts.md` at the start of spec planning -2. Match triggers - Check if the feature description matches any expert triggers -3. Auto-invoke when matched - If triggers match, invoke with `skill: "{expert-name}"` -4. Incorporate guidance - Use expert recommendations to: - - Inform BEFORE/AFTER examples with framework-specific patterns - - Create DO/DON'T sections based on common pitfalls - - Define type contracts that follow framework conventions +Match triggers — check if the feature description or slice content touches any outside expert's domain. Auto-invoke when matched. -### How to Use Signals When Writing Slices +Use outside expert guidance to: +- Inform BEFORE/AFTER examples with framework-specific patterns +- Create DO/DON'T sections based on common pitfalls +- Define type contracts that follow framework conventions -1. Read `references/signals.md` at the start of spec planning -2. For each slice being planned: - - Determine if the slice needs runtime validation - - Match slice type against signal triggers - - Write Signal section into the slice +### Check availability -### Signal Section Format - -Every slice must include a Signal section after the Objective: - -```markdown -# Slice X.Y: Name - -## Objective - -... - -## Signal - -**Signal Skill:** {signal-skill-name | None} - -**Expected Behavior:** -- Specific validations for this slice -- what should succeed when correctly implemented - -## BEFORE/AFTER Directory Structure -[rest of slice...] -``` - ---- \ No newline at end of file +If `/expert` is absent, skip silently — no fallback needed. If no `/expert-*` triggers match, skip. Never fail planning on expert unavailability. \ No newline at end of file diff --git a/skills/sdd/spec-planning/references/signals.md b/skills/sdd/spec-planning/references/signals.md deleted file mode 100644 index ee11f34..0000000 --- a/skills/sdd/spec-planning/references/signals.md +++ /dev/null @@ -1 +0,0 @@ -# Signals \ No newline at end of file diff --git a/skills/sdd/spec-validate/SKILL.md b/skills/sdd/spec-validate/SKILL.md index 507d426..1d3ea47 100644 --- a/skills/sdd/spec-validate/SKILL.md +++ b/skills/sdd/spec-validate/SKILL.md @@ -156,14 +156,14 @@ For each candidate finding, classify as **impactful** or **nitpick**: - **Impactful** — Would mislead the implementing agent. Examples: - Missing or wrong type contracts (interfaces, schemas) - Incorrect BEFORE/AFTER file paths - - Ambiguous Signal section (no clear validation command) + - Ambiguous final-slice Success Criteria (no clear PRD-test command) - Missing forward-looking requirements that block downstream slices - Security gaps in DO/DON'T examples - Wrong file path references - Missing slice dependency in the Dependency Map - Broken slice DAG (cycle, dangling reference) - Slice that contradicts the PRD's definition of done - - Slice missing the run-prd-test gate (the final slice's Signal must invoke `./prds//run-prd-test.sh` and require exit 0 as the PRD-completion criterion) + - Final slice missing Success Criteria (must invoke `./prds//run-prd-test.sh` and require exit 0 as the PRD-completion criterion) **→ Apply the fix.** @@ -197,7 +197,7 @@ Structure: ## Subagent consensus ### 3/3 (Very High Confidence) -- **[Applied]** Slice 1.2 / Signal section — finding text — fix applied: +- **[Applied]** Slice 1.2 / Success Criteria — finding text — fix applied: - **[Skipped: nitpick]** Slice 2.1 / Wording — finding text — reason for skip ### 2/3 (High Confidence) diff --git a/subagents/slice-implementer.md b/subagents/slice-implementer.md index 1456678..74d62d0 100644 --- a/subagents/slice-implementer.md +++ b/subagents/slice-implementer.md @@ -8,7 +8,7 @@ permissionMode: bypassPermissions # Slice Implementer -You are a focused slice implementation agent. The `implement-slice` skill is preloaded — follow its workflow for implementation, signal validation, and unit tests. +You are a focused slice implementation agent. The `implement-slice` skill is preloaded — follow its workflow for implementation, unit tests, and reflection. ## Working Directory @@ -25,16 +25,15 @@ All file paths in the slice spec are relative to this directory. 1. **No git commands** — Do NOT run `git add`, `git commit`, `git push`, or any other git commands. The orchestrator handles all git operations after you finish. 2. **No PRs** — Do NOT create pull requests. 3. **No worktree commands** — Do NOT run `git worktree` commands. You are already in a worktree (or the correct branch). -4. **Stay in scope** — Only modify files specified by or implied by your assigned slice. Do not modify files outside your slice scope. +4. **Stay in scope** — Only modify files specified by or implied by your assigned slice. Exception: during the Reflect step, editing files under `.claude/skills/expert/references/` is explicitly in-scope. 5. **No human prompts** — Do NOT use `AskUserQuestion`. No human is in the loop. -6. **Honor `max_signal_iterations`** — If the prompt provides this value (default 3), pass it to `implement-slice` so the inner signal-fix-retry loop is bounded. Return FAILURE if the cap is hit; do not loop indefinitely. ## Workflow 1. Read the slice spec file (path provided in your prompt) -2. Follow the `implement-slice` workflow: Implement → Signal Validation → Unit Tests +2. Follow the `implement-slice` workflow: Implement → Unit Tests → Reflect 3. Report your result: - - **SUCCESS**: All code implemented, tests pass. Briefly list key files created/modified. + - **SUCCESS**: All code implemented, tests pass, Reflect outcome (no-op | add | edit | delete). Briefly list key files created/modified (including any Expert reference files from Reflect). - **FAILURE**: Describe what went wrong and where you stopped. ## Spec File Access From e3f2c499ce8f5e4af45bbf3e59359a0fd4bb7b96 Mon Sep 17 00:00:00 2001 From: codeisme621 Date: Fri, 3 Jul 2026 19:29:50 -0500 Subject: [PATCH 02/14] simplify /learn and /expert --- docs/2-spec-driven-development.md | 3 +- docs/4-continuous-improvement.md | 44 ++-- docs/5-the-human-loop.md | 2 +- docs/README.md | 2 +- .../harness/harness-init/assets/learn-tick.sh | 4 +- .../harness-init/assets/poll-and-dispatch.sh | 2 +- skills/harness/learn/SKILL.md | 196 ++++++++++++------ .../learn/references/agents-md-guidance.md | 5 + skills/harness/learn/references/consensus.md | 35 ---- .../harness/learn/references/expert-shards.md | 44 ---- .../learn/references/expert-structure.md | 129 ++++++++++++ .../learn/references/invariant-discovery.md | 21 +- skills/harness/learn/references/reconcile.md | 138 ++++++++++++ .../harness/learn/references/routing-rules.md | 42 +++- .../learn/references/wikilink-convention.md | 68 ++++++ .../learn/scripts/check-expert-links.sh | 102 +++++++++ skills/human-loop/evaluate-sessions/SKILL.md | 6 +- .../evaluate-sessions/references/evals.md | 2 +- .../evaluate-sessions/references/outcomes.md | 10 +- .../references/trace-reading.md | 2 +- 20 files changed, 669 insertions(+), 188 deletions(-) delete mode 100644 skills/harness/learn/references/consensus.md delete mode 100644 skills/harness/learn/references/expert-shards.md create mode 100644 skills/harness/learn/references/expert-structure.md create mode 100644 skills/harness/learn/references/reconcile.md create mode 100644 skills/harness/learn/references/wikilink-convention.md create mode 100755 skills/harness/learn/scripts/check-expert-links.sh diff --git a/docs/2-spec-driven-development.md b/docs/2-spec-driven-development.md index 4cbe505..b745b8c 100644 --- a/docs/2-spec-driven-development.md +++ b/docs/2-spec-driven-development.md @@ -168,7 +168,8 @@ knows whether it's on track as it goes, not after. A repeatable way to take one feature from idea to working code while keeping the agent's window full of exactly the right context and nothing else: knowledge defined once and pulled on demand, planning externalized and disclosed -progressively, validation by consensus, implementation gated by signal. All of +progressively, validation by consensus, implementation verified by unit tests +and fed back through Reflect. All of it framework-agnostic, all of it usable on its own. --- diff --git a/docs/4-continuous-improvement.md b/docs/4-continuous-improvement.md index 45f282c..30e96cf 100644 --- a/docs/4-continuous-improvement.md +++ b/docs/4-continuous-improvement.md @@ -15,9 +15,9 @@ own long-term memory.** The next feature starts knowing what the last one taught ```mermaid flowchart LR Merge([Merge to main]) --> Learn["/learn\nreads the merged diff"] - Learn --> Vote{Consensus:\nanything worth\nremembering?} - Vote -->|no — common| Noop[No-op. Most merges\nteach nothing durable.] - Vote -->|yes| Route[Route each fact to\nexactly one destination] + Learn --> Reconcile{Reconcile against\ncurrent memory:\nanything to add,\nedit, or delete?} + Reconcile -->|no — common| Noop[Nothing to learn.\nMost merges teach\nnothing durable.] + Reconcile -->|yes| Route[Route each change to\nexactly one destination] Route --> PR["learn/ PR\nyou review and merge"] ``` @@ -74,14 +74,15 @@ keeping routes to **exactly one** place: |---|---|---| | **A lint** (`scripts/lints/*`) | The rule is mechanically checkable — pass/fail needs no judgment | Enforced on every PR forever; the error message doubles as a fix prompt | | **Eager prose** (`AGENTS.md`) | It must be known *before* an agent would think to consult the Expert, and clears a strict five-part bar | Paid every session — the high bar | -| **Lazy prose** (an Expert shard) | It's useful when *deliberately reasoning* about an area | Paid only when consulted — the usual home | +| **Lazy prose** (an Expert reference file) | It's useful when *deliberately reasoning* about an area | Paid only when consulted — the usual home | | **Nowhere** | It's inferable from the code, taste-only, or transient | — | -Most facts go to the last two. A 0/3 consensus — "this merge teaches nothing -durable" — is a **common and correct** outcome, not a failure: vuln fixes, -refactors that don't change shape, and routine bug fixes usually change no memory -at all. The system improves by accumulating signal, not noise, and *preferring -nothing over noise* is what keeps the Expert worth reading. +Most facts go to the last two. A **nothing-to-learn** outcome — "this merge +teaches nothing durable" — is a **common and correct** result, not a failure: +vuln fixes, refactors that don't change shape, and routine bug fixes usually +change no memory at all, so `/learn` prints `nothing to learn` and opens no PR. +The system improves by accumulating signal, not noise, and *preferring nothing +over noise* is what keeps the Expert worth reading. ## Lints — the memory an agent cannot ship past @@ -105,15 +106,22 @@ lint only on recurrence, and a drafted lint **must pass against the just-merged code** before it's wired in (the inverse of `/intent`'s right-reason check — a lint that reddens the merge it was born from is wrong). -## Consensus gates the write - -Before anything changes, `/learn` spawns a few cheap reviewers that read the -merged diff against current memory and vote, per surface, on whether anything -*must* change. Only changes that clear the threshold survive. It's the same -consensus pattern `/spec-validate` uses in Chapter 2, pointed at a different -question — and it's cheap insurance against corrupting long-term memory on every -commit. Everything that does survive lands on a reviewable, revertible PR. You -stay the final gate. +## Reconcile, don't accumulate + +Memory is a *current model of `main`*, not an append-only log — so `/learn` doesn't +just add. On every merge it runs a three-pass reconcile against the merged diff, +inline in the main agent (no subagent voting): it **deletes** reference files whose +anchor code is gone, resolves **contradictions** between files that now disagree, +and **edits** claims the diff has invalidated. Adds, edits, and deletes all ride +on the same `learn/` PR, each with a one-line justification citing the diff +hunk that motivated it — if it can't be justified from the diff, it's dropped. +That inline justification is the bar that keeps memory honest, and everything that +survives lands on a reviewable, revertible PR. You stay the final gate. + +Inside the Expert, the files are kept small and topic-focused, cross-linked with +`[[wikilinks]]` so an agent reads the one-line index, opens only what's relevant, +and follows links to the rest — progressive disclosure, so consulting memory +never means loading all of it. ## What you have at the end of Layer 2 diff --git a/docs/5-the-human-loop.md b/docs/5-the-human-loop.md index bc1e217..a772030 100644 --- a/docs/5-the-human-loop.md +++ b/docs/5-the-human-loop.md @@ -140,7 +140,7 @@ What you find turns into two durable outcomes — the **flywheel**: regression test over the harness's **own skills and context** (the analog of testing a prompt), distinct from the PRD runner, which tests the product. - **Context fixes** — when a piece of context misled an agent, fix the Expert - shard, the `AGENTS.md` pointer, or the skill. + reference file, the `AGENTS.md` pointer, or the skill. This is the moment the framing of the whole book becomes literal: every PR the harness builds is a graded trial of your project's context, and every eval you diff --git a/docs/README.md b/docs/README.md index 1364be5..bfacac4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -42,7 +42,7 @@ as you climb — but you can stop on any rung. over. 2. **[Spec-Driven Development](./2-spec-driven-development.md)** *(Layer 1)* — how Context Specs applies context engineering to a single feature: experts, specs, - temporal slicing, signal, consensus validation. The foundation, usable on its + temporal slicing, reflection, consensus validation. The foundation, usable on its own. 3. **[The agent harness](./3-the-agent-harness.md)** *(Layer 2)* — file a PRD, walk away, come back to a finished PR. The autonomous loop, and why you can diff --git a/skills/harness/harness-init/assets/learn-tick.sh b/skills/harness/harness-init/assets/learn-tick.sh index a2c72bb..4726a59 100644 --- a/skills/harness/harness-init/assets/learn-tick.sh +++ b/skills/harness/harness-init/assets/learn-tick.sh @@ -54,10 +54,10 @@ signal_learn_review() { { echo "## /learn session — why memory changed" echo - echo "These memory edits (Expert shards, invariants, AGENTS.md pointers," + echo "These memory edits (Expert reference files, invariants, AGENTS.md pointers," echo "candidate lints) were written by a headless \`/learn\` over the merged" echo "diff. If a routing call here looks wrong — a fact in the wrong surface," - echo "an overfit lint, an Expert shard that says too much — open the trace" + echo "an overfit lint, an Expert reference file that says too much — open the trace" echo "below to see exactly what \`/learn\` read and how it decided, before you" echo "accept or revise it." echo diff --git a/skills/harness/harness-init/assets/poll-and-dispatch.sh b/skills/harness/harness-init/assets/poll-and-dispatch.sh index 9f713cd..aec3612 100755 --- a/skills/harness/harness-init/assets/poll-and-dispatch.sh +++ b/skills/harness/harness-init/assets/poll-and-dispatch.sh @@ -129,7 +129,7 @@ signal_stuck() { echo "## Diagnosis-first" echo echo "Your **first** job is not the code — it is to identify which piece of" - echo "context (\`AGENTS.md\`, an Expert shard, a spec, or the PRD) misled the" + echo "context (\`AGENTS.md\`, an Expert reference file, a spec, or the PRD) misled the" echo "agent or was missing. Correct it on this branch *before* the code fix;" echo "the merge carries both into main and \`/learn\` picks up the context fix." echo diff --git a/skills/harness/learn/SKILL.md b/skills/harness/learn/SKILL.md index 88da022..18fc6cf 100644 --- a/skills/harness/learn/SKILL.md +++ b/skills/harness/learn/SKILL.md @@ -1,6 +1,6 @@ --- name: learn -description: Update the project's long-term memory after a merge to main. Reads the merged diff and the current memory, then writes Expert shards, discovered invariants, candidate lints, and AGENTS.md pointers — all on a reviewable learn/ PR. Use post-merge (the harness invokes it automatically) or with --rebuild to regenerate memory from scratch. Triggers - learn, expert-update, update memory, update expert, post-merge memory, self-improve (project) +description: Update the project's long-term memory after a merge to main. Reads the merged diff and reconciles the current memory — adding, editing, and deleting Expert reference files — then drafts candidate lints and AGENTS.md pointers. Opens a reviewable learn/ PR, or prints "nothing to learn" and exits if the merge produced no material change. Use post-merge (the harness invokes it automatically) or with --rebuild to regenerate memory from scratch. Triggers - learn, expert-update, update memory, update expert, post-merge memory, self-improve (project) --- # learn @@ -42,28 +42,42 @@ into main with the feature merge, and **you observe them in the diff you read**. the bar for putting something in AGENTS.md is **far higher** than for the Expert. - **P3 — The four destinations.** Every fact worth remembering routes to exactly one place: a **lint** (if mechanically checkable), **eager prose** (AGENTS.md, if - it clears the high bar), **lazy prose** (an Expert shard), or **nowhere**. Most - things go nowhere or to the Expert. See `references/routing-rules.md`. + it clears the high bar), **lazy prose** (an Expert reference file — one of + `how-to-*` / `concept-*` / `pattern-*` / `invariant-*` / `example-*`), or + **nowhere**. Most things go nowhere or to the Expert. See + `references/routing-rules.md` and `references/expert-structure.md`. - **P4 — Map, not encyclopedia.** AGENTS.md is the table of contents that *points into* the Expert; it never duplicates it. A monolithic AGENTS.md rots, crowds out the task, and turns "everything important" into "nothing important." Keep it a map. See `references/agents-md-guidance.md`. -- **P5 — Consensus gates a write.** A few cheap reviewers vote per surface before - anything changes. Routine merges (vuln fixes, refactors that don't change shape) - typically produce no change — that's correct, not a failure. See - `references/consensus.md`. +- **P5 — Progressive disclosure inside the Expert.** Reference files are small and + topic-focused, cross-linked via Obsidian `[[wikilinks]]`. SKILL.md is an index — + one line per file. An agent reads the index, opens only what's relevant, then + follows wikilinks to discover related context. See + `references/expert-structure.md` and `references/wikilink-convention.md`. - **P6 — Invariants are discovered, then promoted.** You may notice architectural - rules the codebase upholds. Record them as prose first; flag the mechanically - checkable ones as candidate **lints** (the highest-value memory, because a lint - is a rule the agent *cannot* ship past). See `references/invariant-discovery.md`. + rules the codebase upholds. Record each as its own `invariant-.md` file + (one rule per file); flag the mechanically checkable ones as candidate **lints** + (the highest-value memory, because a lint is a rule the agent *cannot* ship + past). See `references/invariant-discovery.md`. - **P7 — Human-authored memory edits are authoritative.** When the merged diff - *already* touches AGENTS.md, an Expert shard, or a spec, treat those changes as - **ground truth, not as a proposal to second-guess.** They came from a human - resolving a STUCK or making a deliberate correction. Your job there is to - *extend* (what else, given this correction, now needs to change?) — not to - vote on whether to apply it. -- **P8 — Reviewable, revertible, human-merged.** Everything lands on `learn/` - with a changelog entry citing the merge. Never auto-merge. + *already* touches AGENTS.md, an Expert reference file, or a spec, treat those + changes as **ground truth, not as a proposal to second-guess.** They came from a + human resolving a STUCK or making a deliberate correction. Your job there is to + *extend* (what else, given this correction, now needs to change?) — not to vote + on whether to apply it. +- **P8 — Reviewable, revertible, human-merged.** Everything lands on a `learn/` + PR. Never auto-merge. +- **P9 — Reconcile, don't accumulate.** Memory is a *current model of main*, not + an append-only log. Every run must look for deleted concepts (the code is gone → + the reference file goes), inter-file contradictions (two files disagree → merge + or scope-qualify), and claims invalidated by the merged diff. **Adds, edits, and + deletes** all ride on the same PR. See `references/reconcile.md`. +- **P10 — Nothing to learn is a valid outcome.** Most merges produce nothing for + memory. When `reconcile` finds zero adds, edits, deletes, AGENTS.md pointer + changes, or candidate lints, print `learn: nothing to learn from , skipping + PR` to stdout, exit 0, and do not push a branch or open a PR. The outer loop + advances `refs/harness/last-learned` regardless. ## How to run this skill @@ -71,82 +85,125 @@ Read the seam references before acting; they are the hackable contract a project tunes to its taste: - `references/routing-rules.md` — the four destinations + the five-predicate test - for eager placement + the line-count caps. *(Primary hackable seam.)* -- `references/expert-shards.md` — the shard taxonomy and templates. + for eager placement + the five sub-destinations for the Expert + the line-count + caps. *(Primary hackable seam.)* +- `references/expert-structure.md` — the flat prefix-named layout, the five + prefixes, the SKILL.md index, the bootstrap seed list. +- `references/wikilink-convention.md` — the `[[basename]]` cross-link syntax used + inside `expert/references/` and the lint that enforces it. +- `references/reconcile.md` — the three-pass add/edit/delete logic plus the + nothing-to-learn early exit. - `references/agents-md-guidance.md` — map-not-manual; which folders earn a nested AGENTS.md; the freshness contract. - `references/invariant-discovery.md` — how to surface invariants and draft lints without overfitting. -- `references/consensus.md` — the voting threshold (2/3 default) and how to run it. ## The flow ### Step 0 — Mode + idempotency Determine mode: -- **Bootstrap** — no `.claude/skills/expert/` exists (or `--rebuild`): create the - Expert from scratch by scanning committed code, seed all shards + the root - `AGENTS.md`. This is also the recovery path (see `--rebuild`). -- **Incremental** — the Expert exists: reconcile against the merged diff. +- **Bootstrap** — `.claude/skills/expert/` is empty (no `SKILL.md` index inside), + or `--rebuild` was passed: create the Expert from scratch by scanning committed + code, seed the minimum-viable file set (see `references/expert-structure.md`) + + the root `AGENTS.md`. This is also the recovery path. Check for the presence + of `SKILL.md` inside the dir, not for the dir itself. +- **Incremental** — the Expert exists (contains a `SKILL.md`): reconcile against the merged diff. Idempotency: if `learn/` already exists on origin, another node handled this merge — exit cleanly. (The memory loop pre-checks this too, via `git ls-remote`.) ### Step 1 — Gather -Read: the diff for `--since ..--sha `; the current Expert shards -(`.claude/skills/expert/references/*.md`); the AGENTS.md files the diff touches -(root + any in changed folders); and the PRD(s)/spec(s) for the merged feature if -present (`prds//`, `specs//`) for the *why*. - -**Notice whether the diff itself touches memory files** (AGENTS.md, Expert shards, -spec sections). If so, you're looking at a human's context correction — see P7; -those changes are ground truth. - -### Step 2 — Consensus -Spawn 2–3 cheap parallel reviewers (`references/consensus.md`). Each reads the diff -+ current memory and votes, **per surface**, on whether anything must change: -shards, invariants, AGENTS.md. (No votes against human-authored memory edits — P7.) -Keep only changes that clear the threshold. A 0/3 on every surface is a valid, -common outcome — log it and no-op. +Read: the diff for `--since ..--sha `; the current Expert reference +files (`ls .claude/skills/expert/references/*.md` plus their contents); the +AGENTS.md files the diff touches (root + any in changed folders); and the +PRD(s)/spec(s) for the merged feature if present (`prds//`, `specs//`) for +the *why*. + +**Notice whether the diff itself touches memory files** (AGENTS.md, Expert +reference files, spec sections). If so, you're looking at a human's context +correction — see P7; those changes are ground truth. + +### Step 2 — Reconcile +Run the three-pass reconcile (`references/reconcile.md`) in the main agent — no +subagent fanout. Produce three candidate lists: `adds[]`, `edits[]`, `deletes[]`. +Every candidate carries a **one-line justification** citing the diff hunk +(file:line range) or the contradicting reference file. If you can't write the +justification, drop the candidate. + +The three passes: +1. **Deleted-concept** — references whose anchor code is gone → `delete`. +2. **Inter-file contradiction** — pairs that disagree → rewrite both to + scope-qualify, merge them, or drop the stale one. +3. **Diff-invalidates-file** — references contradicted by the merge → `edit`. ### Step 3 — Route -For each surviving candidate fact, apply `references/routing-rules.md`: lint / -eager AGENTS.md / lazy Expert shard / nowhere. When in doubt, prefer the Expert -(cheap) over AGENTS.md (eager), and prefer *nothing* over noise. +For each surviving candidate, apply `references/routing-rules.md`: lint / +eager AGENTS.md / lazy Expert reference (then pick the prefix: `how-to-*` / +`concept-*` / `pattern-*` / `invariant-*` / `example-*`) / nowhere. When in +doubt, prefer the Expert (cheap) over AGENTS.md (eager), and prefer *nothing* +over noise. + +### Step 3.5 — Nothing-to-learn check +If after Reconcile + Route the totals are empty: + +``` +len(adds) + len(edits) + len(deletes) == 0 +AND no AGENTS.md pointer change +AND no candidate lint +``` + +…print `learn: nothing to learn from , skipping PR` to stdout, exit 0. +Do **not** push a branch, do **not** open a PR, do **not** commit. The outer +loop advances `refs/harness/last-learned` regardless. ### Step 4 — Write -- **Expert shards** — apply diffs to the relevant shard(s); add to `core-files.md`, - `patterns.md`, etc. -- **invariants.md** — add any discovered hard rules. For mechanically checkable - ones, draft a candidate lint (code + remediation-message-as-prompt) under - `scripts/lints/` and wire it into `scripts/local-checks.sh`. **The drafted lint - MUST pass against the just-merged code before you include it** — run it; if it - fails on current main it's wrong (the inverse of `/intent`'s right-reason check). +- **Expert references** — apply adds/edits/deletes to + `.claude/skills/expert/references/`. New files use the prefix layout + (`how-to-.md`, `concept-.md`, etc.). Cross-link to related + files with `[[wikilinks]]` (no path, no extension). Update + `.claude/skills/expert/SKILL.md`'s one-line-per-file index to match the new set. +- **Invariants** — each discovered hard rule lands as its own + `invariant-.md` (one rule per file). For mechanically checkable ones, + draft a candidate lint (code + remediation-message-as-prompt) under + `scripts/lints/` and wire it into `scripts/local-checks.sh`. **The drafted + lint MUST pass against the just-merged code before you include it** — run it; + if it fails on current main it's wrong. - **AGENTS.md** — update the relevant map's pointer(s). Propose a *new* nested AGENTS.md only when the merge introduced a folder-local rule that clears the - five-predicate bar and no file exists. Stay under the caps. + five-predicate bar and no file exists. Stay under the caps. AGENTS.md uses + regular `[text](path)` markdown links — **not** wikilinks. ### Step 5 — Validate -Run `scripts/check-agents-md.sh` (referenced paths exist, cross-links resolve, -under caps). Re-run any drafted lint against current main (must pass). +Run `scripts/check-agents-md.sh` (AGENTS.md pointers exist, cross-links resolve, +under caps) and `scripts/check-expert-links.sh` (every `[[wikilink]]` resolves +to a file in `expert/references/`). Re-run any drafted lint against current +main (must pass). -### Step 6 — Changelog + PR -Append a `changelog.md` entry citing the merge sha and listing every surface -touched and the consensus vote. Open the `learn/` PR. Done. +### Step 6 — Open PR +Commit the changes and open the `learn/` PR. The PR body lists every +add/edit/delete with its one-line justification. **No changelog file is +appended** — the git history of `learn/` PRs is the changelog. ## Invocation & output contract - **Invoked by:** the memory loop, `claude -p "/learn --since --sha "`, inside the `../-harness-learn` worktree. The `--since` is the `refs/harness/last-learned` watermark (how far memory has already been digested); `--sha` is current `origin/main`. Also runnable by a human with `--rebuild` - (regenerate memory from main). -- **Writes:** under `.claude/skills/expert/` (shards incl. `invariants.md` and - `changelog.md`), `scripts/lints/*` + `scripts/local-checks.sh` wiring, and - `AGENTS.md` files across the repo. -- **Completion signal:** the pushed `learn/` branch + open PR. Idempotent via - `git ls-remote origin learn/`. After the PR opens, the memory loop advances - `refs/harness/last-learned` to `` (atomic CAS) and pauses new runs until you - merge or close the PR. -- **Session trail:** after the PR opens, the memory loop (`signal_learn_review`) + (regenerate memory from main) or `--dry-run` (print the candidate set plus + justifications; open no PR; useful for evaluation runs). +- **Writes:** under `.claude/skills/expert/` (prefix-named reference files plus + the `SKILL.md` index), `scripts/lints/*` + `scripts/local-checks.sh` wiring, + and `AGENTS.md` files across the repo. **No `changelog.md`** — the git history + of `learn/` PRs is the changelog. +- **Completion signal — two valid outcomes:** + - **PR opened.** The pushed `learn/` branch + open PR. Idempotent via + `git ls-remote origin learn/`. After the PR opens, the memory loop + advances `refs/harness/last-learned` to `` (atomic CAS) and pauses new + runs until you merge or close the PR. + - **Nothing to learn.** Stdout `learn: nothing to learn from , skipping + PR`; exit 0; no branch pushed. The memory loop advances the watermark + regardless, so the next merge is picked up cleanly. +- **Session trail:** when a PR opens, the memory loop (`signal_learn_review`) attaches this run's headless `claude -p` session as a PR comment, so the human evaluating the memory changes can open the trace and troubleshoot *why* `/learn` routed a fact as it did. No action needed in this skill — the loop posts it. @@ -158,8 +215,15 @@ touched and the consensus vote. Open the `learn/` PR. Done. the caps (P4). - **Never include a candidate lint you haven't run against current main.** A lint that reddens the merge it was born from is wrong. -- **Never frame an invariant as taste.** If it needs judgment, it's a pattern - (Expert), not an invariant (lint/hard rule). +- **Never frame an invariant as taste.** If it needs judgment, it's a `pattern-*` + file (Expert), not an `invariant-*` file (lint/hard rule). - **Never second-guess a memory edit that's already in the merged diff** (P7) — the human resolved a STUCK or made a deliberate correction; your job is to *extend* it, not vote on it. +- **Never accumulate without reconciling** (P9). A concept deleted from code is a + reference file deleted in this PR. Inbound wikilinks get rewritten in the same + commit. +- **Never write a wikilink that does not resolve** to a file in + `expert/references/`. `check-expert-links.sh` will fail the PR. +- **Never open a PR for nothing-to-learn** (P10). Print the stdout line, exit 0, + push nothing. diff --git a/skills/harness/learn/references/agents-md-guidance.md b/skills/harness/learn/references/agents-md-guidance.md index 8771782..a951d45 100644 --- a/skills/harness/learn/references/agents-md-guidance.md +++ b/skills/harness/learn/references/agents-md-guidance.md @@ -36,6 +36,11 @@ path it references exists, cross-links resolve, and it's under the line cap. Wir this into `local-checks.sh`/CI so a stale pointer fails the build. This is the same "enforce invariants mechanically" instinct turned on the memory files themselves. +> AGENTS.md uses regular `[text](path)` markdown links — **not** wikilinks. The +> Obsidian-style `[[wikilinks]]` convention is internal to `expert/references/` +> only; it has its own validator (`check-expert-links.sh`). Keep the two link +> styles separate so each validator stays simple. + ## Caps (tweakable, enforced by check-agents-md.sh) - Root: ≤ 150 lines. - Nested: ≤ 80 lines. diff --git a/skills/harness/learn/references/consensus.md b/skills/harness/learn/references/consensus.md deleted file mode 100644 index 70dd0be..0000000 --- a/skills/harness/learn/references/consensus.md +++ /dev/null @@ -1,35 +0,0 @@ -# Consensus - -**Hackable seam.** The voting threshold that gates a memory write. Mirrors the -multi-agent consensus `/spec-validate` already uses, so the project has one mental -model for "a panel decided," not two. - -## Why consensus here -Memory is long-lived and compounding. A wrong write poisons every future session -that reads it. The trade is cheap: a few extra LLM calls per merge in exchange for -not corrupting long-term memory on every commit. Most merges (vuln fixes, refactors -that don't change shape, routine bug fixes) produce **no change** — 0/3 across all -surfaces is the common, correct outcome. - -## How to run it -1. Spawn **2–3** parallel reviewers (cheap model is fine — this is judgment over a - bounded diff, not generation). -2. Give each: the merged diff, the current Expert shards, the touched AGENTS.md - files, and the PRD/spec for the *why*. -3. Each votes **per surface** (shards / invariants / AGENTS.md): does anything - need to change, and if so what? -4. Apply only changes that meet the **threshold (default 2/3)**. Discard 1/3. - -## Tuning -- Raise to **3/3** for a stricter bar (fewer, higher-confidence writes). -- Lower to a single reviewer only for low-stakes projects that want speed over - precision — not recommended for invariant/lint promotion, which should stay - consensus-gated *and* human-confirmed. -- **Human-authored memory edits already in the diff bypass voting** (see SKILL.md - P7) — they're ground truth. Vote on what to *extend*, not whether to apply them. - -## Drift signal -If consensus returns 0/3 for *many* consecutive merges, that's worth noticing: the -Expert may be too coarse to capture what's changing, or the project is genuinely -stable. Either way, it's an observability signal, not a bug — surface it, don't -force a write. diff --git a/skills/harness/learn/references/expert-shards.md b/skills/harness/learn/references/expert-shards.md deleted file mode 100644 index c1f9be1..0000000 --- a/skills/harness/learn/references/expert-shards.md +++ /dev/null @@ -1,44 +0,0 @@ -# Expert shard taxonomy - -**Hackable seam.** A project may add, rename, or split shards. These are the -defaults. The Expert is the project's *lazy* memory — pulled on demand by `/intent`, -`/spec-planning`, `/spec-validate`, and `/implement-*` via the catalog, or read -directly. It is shaped exactly like a framework expert (so it composes with them): - -``` -.claude/skills/expert/ -├── SKILL.md # Expert Mode entry: quick-reference table → references/ -├── references/ -│ ├── architecture.md # Decisions, layering, boundaries, the "why" of the shape -│ ├── verification.md # How features get tested/verified in THIS project -│ ├── patterns.md # Soft DO/DON'T, with examples (taste, judgment) -│ ├── procedural.md # "How to add a new feature here" — the steps -│ ├── core-files.md # Key files & abstractions, with paths -│ ├── invariants.md # HARD rules the codebase upholds (see below) -│ └── changelog.md # Provenance: what /learn changed, when, why, vote -└── scripts/ - └── (optional signal scripts, like any expert) -``` - -## The shard this design adds: invariants.md (hard rules, distinct from patterns.md) - -`patterns.md` is *soft* ("prefer composition here"); `invariants.md` is *hard* -("Repo layer never imports Service"). The distinguishing test: **can it be -mechanically checked?** If yes, it's an invariant and the highest-value ones become -lints (see `invariant-discovery.md`). If it needs judgment, it's a pattern. - -Each invariant entry: the rule, *why* it holds, and — once promoted — a pointer to -its lint (`scripts/lints/.sh`). - -## SKILL.md shape -Mirror the framework-expert shape (`expert-sdd-creator`'s `expert-structure.md`): a -short Expert-Mode entry with a quick-reference table mapping topics → reference -files. The body stays small; the references hold the density. Front-matter -`description` ends with `(project)` and lists triggers so the catalog can activate -it during the SDD phases. - -## Bootstrap / --rebuild -On a fresh project (no Expert) or `--rebuild`, seed every shard by scanning -committed code: derive `core-files.md` from the actual tree, `verification.md` from -the test/CI setup, `architecture.md` from the module layering, `invariants.md` from -rules the code visibly upholds (conservatively — see `invariant-discovery.md`). diff --git a/skills/harness/learn/references/expert-structure.md b/skills/harness/learn/references/expert-structure.md new file mode 100644 index 0000000..63cc8a6 --- /dev/null +++ b/skills/harness/learn/references/expert-structure.md @@ -0,0 +1,129 @@ +# Expert structure + +**Hackable seam.** A project may add, rename, or split files. These are the +defaults. The Expert is the project's *lazy* memory — pulled on demand by `/intent`, +`/spec-planning`, `/spec-validate`, and `/implement-*` via the catalog, or read +directly. + +The Expert is a **flat directory of many small, topic-focused files**, each named +by a prefix that tells the agent (and `/learn`) what kind of memory it is. Files +cross-link to each other with Obsidian-style `[[wikilinks]]` so an agent reading +one file can discover related context by following links. `SKILL.md` is the +**index**: one line per reference file plus a short note about the link convention. + +``` +.claude/skills/expert/ +├── SKILL.md # INDEX: one-line description per reference +└── references/ + ├── how-to-run-the-project.md # procedural SOP + ├── how-to-validate.md # procedural SOP + ├── how-to-e2e-test.md # procedural SOP (setup, exercise, teardown) + ├── concept-architecture.md # semantic + ├── concept-core-files.md # semantic + ├── pattern-.md # soft prefer/avoid (judgment) + ├── invariant-.md # one hard rule per file + └── example-.md # past trace, cited from a real sha +``` + +## The five prefixes + +Each fact `/learn` decides to remember lands in exactly one prefixed file. The +filename slug is the topic; the prefix is the *kind* of memory. + +- **`how-to-.md` — procedural.** A sequence of steps a contributor (or + agent) follows. Imperative voice. Answers "How do I X?" Examples: + `how-to-run-the-project.md`, `how-to-validate.md`, `how-to-e2e-test.md`, + `how-to-add-a-feature.md`. Setup/teardown belongs inside the relevant how-to. + +- **`concept-.md` — semantic (nouns).** The shape of the system, a model, + a definition. Declarative voice. Answers "What is X?" Examples: + `concept-architecture.md`, `concept-core-files.md`, `concept-routing.md`. + +- **`pattern-.md` — semantic (soft rules).** A DO/DON'T that requires + judgment. Has counterexamples. Cannot be mechanically checked. Example: + `pattern-error-handling.md` ("prefer typed errors at boundaries; raw exceptions + fine inside a module"). + +- **`invariant-.md` — semantic (hard rules).** A single rule the codebase + upholds, mechanically checkable in principle. **One rule per file.** Filename + is the rule. Example: `invariant-no-repo-imports-service.md`. The highest-value + invariants get drafted as lints (see `invariant-discovery.md`). + +- **`example-.md` — episodic.** A concrete past trace — a real PR or + merge, input → reasoning → output. Cited from a real sha. Never synthetic. + Acts as a few-shot demonstration. Example: + `example-added-search-endpoint-2024-q3.md`. + +The split exists so an agent reading the SKILL.md index can ask one question of +each file ("does this topic apply now?") and open only what's relevant — instead +of paging through a 500-line `patterns.md` for one fact. + +## Wikilinks between reference files + +Reference files cross-link to each other with **Obsidian-style `[[wikilinks]]`**: +two square brackets around the *basename of another file in `references/`*, no +extension, no path. + +```markdown +The e2e flow stands up the test DB; see [[how-to-run-the-project]] for the +non-test boot path, and [[invariant-no-repo-imports-service]] for why the +fixture loader lives in `test/` and not `repo/`. +``` + +Resolution: `[[name]]` → `references/name.md`. The agent already knows how to +traverse these — wikilinks are a near-universal convention. + +`scripts/check-expert-links.sh` mechanically validates every wikilink resolves +to a file in the same directory. Broken links fail the PR. See +`wikilink-convention.md` for the formal spec. + +> AGENTS.md does **not** use wikilinks. It uses regular `[text](path)` markdown +> links so `check-agents-md.sh` keeps working unchanged. Wikilinks are an +> internal Expert-only convention. + +## SKILL.md as the index + +`SKILL.md` is generated by `/learn` and is a thin **catalog**, not a knowledge +file. Body: + +1. A one-paragraph header naming the project and stating the wikilink convention. +2. A table: `file | one-line description`. One row per reference file in the + directory. + +That's it. An agent reads the index, decides which references look relevant to +the task at hand, opens those, then follows wikilinks from there. + +The front-matter `description` ends with `(project)` and lists triggers so the +catalog can activate the Expert during the SDD phases. + +## Bootstrap / `--rebuild` + +On a fresh project (no Expert) or when invoked with `--rebuild`, seed a small +**minimum viable Expert** by scanning committed code. Bias toward fewer, broader +files; the incremental post-merge path will split them later when topics get +specific. + +**Always-seed (5 files):** + +1. `how-to-run-the-project.md` — derived from `package.json` / `Makefile` / + `pyproject.toml` / equivalent entry-points. +2. `how-to-validate.md` — derived from `scripts/local-checks.sh` and CI config. +3. `how-to-add-a-feature.md` — the SDD skill chain order for this project. +4. `concept-architecture.md` — module layering from the directory scan. +5. `concept-core-files.md` — key files and abstractions with paths. + +**Conditionally-seed (only on clear visible signal):** + +- `how-to-e2e-test.md` — if end-to-end tests exist. +- `concept-verification.md` — if testing/CI is non-trivial enough to warrant a + separate file from `how-to-validate.md`. +- One `invariant-.md` per rule the code *visibly* upholds. Skip on + uncertainty; let post-merge discovery promote them. +- `pattern-*.md` — **default to zero on bootstrap.** Patterns emerge from + recurring evidence across merges, not from one snapshot. +- `example-*.md` — **zero on bootstrap.** Episodic memory needs real past + experiences, not synthetic ones. + +**Soft cap: ~15 files total** on bootstrap. If the scan suggests more, fold +related items into one `concept-*.md` and let `/learn` split it later when a +topic genuinely warrants its own file. diff --git a/skills/harness/learn/references/invariant-discovery.md b/skills/harness/learn/references/invariant-discovery.md index dbe59dd..bf2e438 100644 --- a/skills/harness/learn/references/invariant-discovery.md +++ b/skills/harness/learn/references/invariant-discovery.md @@ -72,23 +72,28 @@ check would reward). - **Structured logging only** — no `console.log(`/`print(` in `src/`. - **Naming/format** — migration filenames match `^\d{14}_`. - **File-size cap / public-API drift** — `wc -l` ceiling; exports match `openapi.yaml`. -- **Memory freshness** — `check-agents-md.sh` itself (referenced paths exist). +- **Memory freshness** — `check-agents-md.sh` (AGENTS.md pointers exist) and + `check-expert-links.sh` (Expert wikilinks resolve). ## What stays prose (NOT a lint) Anything needing judgment: "is this the right abstraction?", "prefer composition -here." Those are `patterns.md` (Expert), or — if pre-emptively load-bearing — -AGENTS.md. The test: **if pass/fail is unambiguous, lint it; if it needs taste, it -stays prose.** +here." Those live in `pattern-.md` files in the Expert, or — if pre-emptively +load-bearing — AGENTS.md. The test: **if pass/fail is unambiguous, lint it; if it +needs taste, it stays prose.** ## The discipline (avoid overfitting) A discovered "invariant" can be an incidental pattern, or a quirk of the current model's failures rather than a real codebase property. So: -1. **Consensus-gate it** like every `/learn` write. -2. **Prose first, lint on recurrence.** First sighting → record in `invariants.md` - and flag a candidate lint. Same invariant seen across merges → promote to an - enforced lint. One occurrence is a pattern; repetition is an invariant. +1. **Justify it.** In a single inline pass, write a one-line justification citing + the diff hunk (file + line range) that motivated this rule. If you can't, drop + it. This is the inline replacement for the old consensus gate — same bar, + applied by the main agent. +2. **Prose first, lint on recurrence.** First sighting → record as a new + `invariant-.md` (one rule per file) and flag a candidate lint. Same + invariant seen across merges → promote to an enforced lint. One occurrence is + a pattern; repetition is an invariant. 3. **Frame the *reason*.** "Repo→Service imports break the build because layers are compiled bottom-up" survives model upgrades; a bare prohibition doesn't. 4. **The drafted lint MUST pass current main.** Run it against the just-merged code diff --git a/skills/harness/learn/references/reconcile.md b/skills/harness/learn/references/reconcile.md new file mode 100644 index 0000000..4f77128 --- /dev/null +++ b/skills/harness/learn/references/reconcile.md @@ -0,0 +1,138 @@ +# Reconcile — the new write logic + +**Hackable seam.** How `/learn` decides what to **add, edit, and delete** in the +Expert. Replaces the old consensus pass: reasoning happens inline in the main +agent (no subagent fanout), but every proposed change carries a one-line +justification cited from the diff or the contradicting reference file. + +## The premise + +Memory must reflect what is true *on main right now* — not what was true at the +last merge plus everything observed since. So every `/learn` run does three +things, in order: + +1. **Add** facts that appear in the merged diff and aren't in the Expert yet. +2. **Edit** existing reference files whose claims are still relevant but + incomplete or outdated. +3. **Delete** reference files whose underlying concept no longer exists in code, + or that contradict a more recent file beyond rescue. + +## The three reconcile passes + +Run these in order, in the main agent (no subagents). Each produces entries on +one of three candidate lists: `adds[]`, `edits[]`, `deletes[]`. Every entry +carries a **one-line justification** citing either a specific diff hunk +(file:line range) or a specific contradicting reference file. If you can't write +the justification, drop the candidate + +### Pass 1 — Deleted-concept pass + +For each `concept-*.md` and `how-to-*.md` in the Expert: + +1. Extract the file's **key code references**: paths it mentions, function or + class names, module identifiers, command names. +2. For each, check whether it still exists post-merge: `git cat-file -e + :`, `git grep -E `, or equivalent. +3. Decide: + - **Wholly gone** (no references survive) → mark **delete**. + - **Partially gone** (some references survive, some don't) → mark **edit**; + prune the dead pointers and update the prose. + - **All present** → no action from this pass. + +Do the same for `invariant-*.md` and `pattern-*.md`: if the rule's anchor code +is gone (the layer, the module, the API surface), the rule is dead. + +### Pass 2 — Inter-file contradiction pass + +Build a list of **topic-related file pairs**: + +- Pairs that share a wikilink (one references `[[the-other]]`). +- Pairs whose slugs share two or more tokens (e.g. `pattern-error-handling.md` + and `how-to-handle-errors.md`). +- Pairs that mention the same code paths or identifiers. + +For each pair, read both files in full and ask: **do they assert opposing +facts?** Common patterns: + +- **Stale + Fresh.** One was written before a refactor; the other after. + Resolution: drop the stale file (`delete`); the fresh one already covers the + current truth. Justification cites the merge sha that made the older claim + false. + +- **Two facets of one rule.** Two files about the same underlying concept that + disagree because they were each scoped narrowly. Resolution: **merge them** + into one file (`add` the merged file, `delete` both originals). Update any + inbound wikilinks. Justification names both prior files. + +- **Both true at different scopes.** Each is correct in its own context. + Resolution: `edit` both to scope-qualify ("inside the repo layer, …"; "at the + service boundary, …"). Justification cites the scope distinction. + +**Default heuristic: rewrite both / scope-qualify.** Drop one only when one is +clearly stale (its anchor code is gone, it predates a refactor that already +landed, or a human-authored P7 edit in this diff supersedes it). Never silently +delete on contradiction — every `delete` shows up in the PR body with its +one-line justification. + +### Pass 3 — Diff-invalidates-file pass + +For each code path touched by the merged diff, scan all references that mention +that path. For each reference: + +- Does the merge **contradict** a claim in the file? → mark **edit**. +- Does the merge **extend** a claim (new module added, new step in a how-to)? + → mark **edit** to incorporate, or **add** a new sibling file if the new + topic deserves its own. +- Does the merge **replace** the concept the file is about? → see Pass 1 (may + become a `delete`). + +## Routing and writing + +After reconcile, each entry on `adds[]` / `edits[]` / `deletes[]` is routed +through `routing-rules.md` to pick its prefix (`how-to-*` / `concept-*` / +`pattern-*` / `invariant-*` / `example-*`) or — for an `add` — to be redirected +to AGENTS.md, a lint, or nowhere instead. + +Write logic: + +- **Add** → create the file, add it to `SKILL.md`'s index, populate wikilinks to + related references. +- **Edit** → rewrite the relevant section. If a wikilink target was renamed or + deleted, fix the inbound link. +- **Delete** → `rm` the file, remove its row from `SKILL.md`'s index, and + rewrite any inbound wikilinks (drop them or repoint). + +`check-expert-links.sh` will fail the PR if any inbound wikilink was missed. +That's the safety net. + +## Nothing to learn + +If after all three passes plus routing the candidate sets are empty: + +``` +len(adds) + len(edits) + len(deletes) == 0 +AND no candidate AGENTS.md pointer change +AND no candidate lint +``` + +…then `/learn` prints: + +``` +learn: nothing to learn from , skipping PR +``` + +…to stdout, exits 0, and does **not** push a branch or open a PR. This is a +valid, common outcome — most merges are routine and produce nothing for memory. +The harness's outer loop advances `refs/harness/last-learned` regardless of +whether a PR opened, so the watermark keeps moving forward. + +## Why no subagent consensus + +The old design ran 2–3 cheap reviewers and required a 2/3 vote. That gated +hallucinations, but at the cost of a fanout step and the parallel review +overhead. The inline justification rule does the same job more cheaply: the +single agent must cite the diff hunk or contradicting file for *every* +candidate. Anything without a citation is dropped. A `--dry-run` flag (for +human-driven evaluation) prints the candidate set with justifications and +opens no PR — useful when a project wants periodic spot-checks on how `/learn` +is reasoning. diff --git a/skills/harness/learn/references/routing-rules.md b/skills/harness/learn/references/routing-rules.md index ce6c03a..d09e779 100644 --- a/skills/harness/learn/references/routing-rules.md +++ b/skills/harness/learn/references/routing-rules.md @@ -10,9 +10,30 @@ to the last two rows. |---|---|---| | **A lint** (`scripts/lints/*` → `local-checks.sh`) | The rule is *mechanically checkable* — pass/fail needs no judgment (layer-dependency direction, "parse at boundaries", naming, no raw SQL interpolation, structured-logging-only, file-size caps) | Best: enforced on every PR forever, and the failure message doubles as a fix prompt. See `invariant-discovery.md`. | | **Eager prose** (`AGENTS.md`) | It clears **all five predicates** below | Paid in tokens on *every* session that touches the folder — strict bar. | -| **Lazy prose** (an Expert shard) | Useful when an agent is *deliberately reasoning* about this area, but not needed pre-emptively | Paid only when consulted — looser bar. The default home for real knowledge. | +| **Lazy prose** (an Expert reference file) | Useful when an agent is *deliberately reasoning* about this area, but not needed pre-emptively | Paid only when consulted — looser bar. The default home for real knowledge. Splits into five sub-destinations (see below). | | **Nowhere** | Inferable from the code, taste-only, or transient | — | +## Sub-routing for lazy prose: the five prefixes + +A fact destined for the Expert lands in exactly one prefixed file. See +`expert-structure.md` for the directory layout. + +| Sub-destination | Use when | +|---|---| +| `how-to-.md` | Procedural SOP — a sequence of steps. Imperative voice. "How do I X?" | +| `concept-.md` | Semantic — a noun, a model, the shape of the system. "What is X?" | +| `pattern-.md` | Soft DO/DON'T requiring judgment. Has counterexamples. Cannot be linted. | +| `invariant-.md` | A single hard rule, mechanically checkable in principle. One rule per file; filename = the rule. The highest-value ones get drafted as lints. | +| `example-.md` | Episodic / few-shot — a *past* concrete trace (PR, merge, debugging session) cited from a real sha. Never synthetic. | + +**Tiebreakers:** + +- A step list → `how-to`. A noun or definition → `concept`. A rule → `invariant` + if linable, else `pattern`. A past trace with a sha → `example`. +- If a fact is *both* procedural and load-bearing as a rule, write both: the + `how-to-*` mentions the rule and wikilinks `[[invariant-*]]`. +- One rule per `invariant-*.md` file — never bundle multiple invariants. + ## The five-predicate test for *eager* (AGENTS.md) placement A fact earns a line in AGENTS.md only if **all five** hold. If any fails, it goes @@ -47,3 +68,22 @@ prefer nothing over noise.** AGENTS.md **points into** the Expert; it never copies it. A pointer ("this folder does X; consult `expert/references/Y.md` before non-trivial work") stays correct as the Expert grows. A copied paragraph drifts. Reference, don't duplicate. + +## Deletes — routing the other direction + +Routing rules also decide when an existing reference file should be **removed**. +A `delete` candidate is justified when one of these holds: + +- **Deleted concept.** The code the file anchors to is gone from main — the + module, route, command, or identifier it cites no longer exists. (See pass 1 + in `reconcile.md`.) +- **Superseded by a fresher file.** Two reference files contradict, and one is + clearly stale (its anchor code is gone, or a more recent merge supersedes its + claim). The stale one is deleted. (See pass 2 in `reconcile.md`.) +- **Merged into another.** Two files covered overlapping topics and have been + combined; the originals are deleted in favor of the merged file. + +Every `delete` carries a one-line justification in the PR body. Inbound +wikilinks must be rewritten or removed in the same PR; +`scripts/check-expert-links.sh` fails the build if any inbound link still +points at a deleted target. diff --git a/skills/harness/learn/references/wikilink-convention.md b/skills/harness/learn/references/wikilink-convention.md new file mode 100644 index 0000000..1055dbc --- /dev/null +++ b/skills/harness/learn/references/wikilink-convention.md @@ -0,0 +1,68 @@ +# Wikilink convention + +**Hackable seam.** The link syntax `/learn` uses inside `expert/references/`, +and the lint that enforces it. AGENTS.md is **out of scope** — it uses regular +markdown links and has its own validator (`check-agents-md.sh`). + +## Why wikilinks + +Reference files cross-link each other (a `how-to-*` file points at a +`[[concept-*]]` it depends on, an `invariant-*` points at the `[[pattern-*]]` it +hardens, etc.). Two options: + +- Regular markdown links: `[text](concept-architecture.md)`. Verbose, ties text + to filename, and rots when files are renamed. +- Wikilinks: `[[concept-architecture]]`. Short, basename-only, near-universal in + Obsidian-style notes. **Agents already know how to traverse these** without + prompting. + +We pick wikilinks for the Expert's internal cross-references because the cost +of one extra link-resolution rule is bought back many times over in +readability and stable refactoring. + +## The spec + +A wikilink is the literal token `[[]]` where `` matches +`[a-z0-9-]+`. + +Resolution: `[[]]` refers to the file `.md` in the **same directory** +as the file that contains the link (i.e. `.claude/skills/expert/references/`). + +- No paths. No leading `./`. No subdirectories. +- No `.md` extension inside the brackets. +- No alias form (`[[slug|display text]]`) for now — keep the syntax minimal. +- The link target file must exist. + +## Valid + +```markdown +For setup, see [[how-to-run-the-project]]. +The repo layer must obey [[invariant-no-repo-imports-service]]. +This pattern complements [[concept-architecture]]. +``` + +## Invalid + +```markdown +See [[./how-to-run-the-project]]. ← no path +See [[how-to-run-the-project.md]]. ← no extension +See [[How-To-Run-The-Project]]. ← lowercase only +See [[how-to-run-the-project|setup guide]]. ← no alias form +See [[expert/how-to-run-the-project]]. ← no directory prefix +``` + +## Enforcement + +`scripts/check-expert-links.sh` (next to `check-agents-md.sh`) walks every +`expert/references/*.md`, extracts every `[[...]]` token, and asserts each +resolves to an existing `.md` file in the same directory. + +- **Broken link → exit 1.** The PR fails. Fix the link or restore the file. +- **Orphan files** (no inbound wikilink from any other reference) → warn only, + do not fail. Top-level concepts can legitimately be orphans. +- **Cycles** (A → B → A) → informational only. Small cycles between mutually + related concepts are fine. + +Wire the script into `scripts/local-checks.sh` next to `check-agents-md.sh` so +the same gate that flags a stale AGENTS.md pointer also flags a stale Expert +wikilink. diff --git a/skills/harness/learn/scripts/check-expert-links.sh b/skills/harness/learn/scripts/check-expert-links.sh new file mode 100755 index 0000000..afd6884 --- /dev/null +++ b/skills/harness/learn/scripts/check-expert-links.sh @@ -0,0 +1,102 @@ +#!/usr/bin/env bash +# check-expert-links.sh — mechanical link gate for the project's lazy memory. +# +# Reference files under .claude/skills/expert/references/ cross-link via Obsidian +# wikilinks ([[basename]] resolving to basename.md in the same directory). Renames, +# deletions, and typos break these silently — this lint makes those failures loud. +# Wire it into scripts/local-checks.sh (and CI) so a broken Expert link fails the +# build. +# +# Checks: +# 1. Every [[]] token in every references/*.md resolves to .md in +# the same directory. +# 2. Slugs match the convention [a-z0-9-]+ (lowercase, hyphenated). +# +# Warns (does NOT fail): +# - Orphan files (no inbound wikilink from any other reference) — top-level +# concepts can legitimately be orphans. +# +# Exit 0 = clean. Exit 1 = at least one broken or malformed link. +# +# The Expert root is tweakable via env; default is .claude/skills/expert. + +set -euo pipefail + +EXPERT_ROOT="${EXPERT_ROOT:-.claude/skills/expert}" +REF_DIR="${EXPERT_ROOT}/references" + +fail=0 +note() { echo "❌ $*" >&2; fail=1; } +warn() { echo "⚠️ $*" >&2; } + +if [[ ! -d "$REF_DIR" ]]; then + echo "no Expert at ${REF_DIR} (nothing to check)" + exit 0 +fi + +mapfile -t files < <(find "$REF_DIR" -maxdepth 1 -type f -name '*.md' 2>/dev/null | sort) + +if (( ${#files[@]} == 0 )); then + echo "no reference files in ${REF_DIR} (nothing to check)" + exit 0 +fi + +# Build the set of valid slugs (filenames without .md) for fast existence check. +declare -A valid_slug +for f in "${files[@]}"; do + base="$(basename "$f" .md)" + valid_slug["$base"]=1 +done + +# Track inbound link counts to surface orphan warnings. +declare -A inbound_count +for f in "${files[@]}"; do + base="$(basename "$f" .md)" + inbound_count["$base"]=0 +done + +slug_re='^[a-z0-9-]+$' + +for f in "${files[@]}"; do + # Extract every [[...]] token. + while IFS= read -r token; do + [[ -z "$token" ]] && continue + # Strip leading [[ and trailing ]] (escape the brackets so bash treats them + # as literals, not as bracket-expression delimiters in the pattern). + slug="${token##\[\[}" + slug="${slug%%\]\]}" + + # Convention check: lowercase, alphanumeric + hyphen, no path, no extension, + # no alias. + if ! [[ "$slug" =~ $slug_re ]]; then + note "$f: malformed wikilink '[[${slug}]]' — slugs must match [a-z0-9-]+ (no paths, no extensions, no aliases). See wikilink-convention.md." + continue + fi + + # Existence check: target file must exist in references/. + if [[ -z "${valid_slug[$slug]:-}" ]]; then + note "$f: wikilink '[[${slug}]]' does not resolve — no file ${REF_DIR}/${slug}.md. Fix the link or restore the file." + continue + fi + + # Don't count self-links as inbound. + src_base="$(basename "$f" .md)" + if [[ "$slug" != "$src_base" ]]; then + inbound_count["$slug"]=$((inbound_count["$slug"] + 1)) + fi + done < <(grep -oE '\[\[[^]]+\]\]' "$f" || true) +done + +# Orphan warnings (informational only — SKILL.md / top-level concepts are +# expected to be orphans). +for slug in "${!inbound_count[@]}"; do + if (( inbound_count[$slug] == 0 )); then + warn "${REF_DIR}/${slug}.md has no inbound wikilinks (orphan — informational only)." + fi +done + +if (( fail )); then + echo "check-expert-links: FAIL" >&2 + exit 1 +fi +echo "check-expert-links: OK (${#files[@]} file(s))" diff --git a/skills/human-loop/evaluate-sessions/SKILL.md b/skills/human-loop/evaluate-sessions/SKILL.md index 428b766..84fae49 100644 --- a/skills/human-loop/evaluate-sessions/SKILL.md +++ b/skills/human-loop/evaluate-sessions/SKILL.md @@ -13,9 +13,9 @@ harness ran to produce it — into two durable outcomes: behaved well or badly given the context it had, freeze that as a runnable check under `evals/`. This is the flywheel Chase/LangSmith describe — *observe a trace → capture it as an eval → fix the prompt → it persists as a regression test* — except the "prompt" - here is the project's **context** (Expert shards, AGENTS.md, a skill's own text). + here is the project's **context** (Expert reference files, AGENTS.md, a skill's own text). - **Context fixes.** When a session reveals that a piece of context **misled** an agent or - was **missing**, fix it — the Expert shard, the AGENTS.md pointer, or the skill — *with* + was **missing**, fix it — the Expert reference file, the AGENTS.md pointer, or the skill — *with* the human, on a branch. `/evaluate-pr` evaluates **what was built** (the change); `/evaluate-sessions` evaluates @@ -86,7 +86,7 @@ not auditing a single PR, you're tuning the project's context so the *whole harn an agent would think to consult the Expert; non-inferable from the code; harmful if violated (breaks behavior/data, not style); stable; and local-or-truly-global. Eager memory is paid in tokens on every session, so the bar is high. - - **Lazy prose (an Expert shard)** — the default home for real knowledge: useful when an + - **Lazy prose (an Expert reference file)** — the default home for real knowledge: useful when an agent *deliberately reasons* about the area, paid only when consulted. - **Nowhere** — inferable from the code, taste-only, or transient. diff --git a/skills/human-loop/evaluate-sessions/references/evals.md b/skills/human-loop/evaluate-sessions/references/evals.md index 535face..006111f 100644 --- a/skills/human-loop/evaluate-sessions/references/evals.md +++ b/skills/human-loop/evaluate-sessions/references/evals.md @@ -48,7 +48,7 @@ If the project has no `evals/` dir yet, create it when you author the first eval # `evals/` — regression tests over this project's harness skills/context Authored by `/evaluate-sessions` when a build trail reveals a skill behaving well or badly -because of this project's context (an Expert shard, an AGENTS.md pointer, a skill's text, a +because of this project's context (an Expert reference file, an AGENTS.md pointer, a skill's text, a spec). Evals test the **harness** ("given this context, does the skill behave?"); `prds// run-prd-test.sh` tests the **product** ("does the feature work?"). Keep them separate. diff --git a/skills/human-loop/evaluate-sessions/references/outcomes.md b/skills/human-loop/evaluate-sessions/references/outcomes.md index ba3e983..f80b82f 100644 --- a/skills/human-loop/evaluate-sessions/references/outcomes.md +++ b/skills/human-loop/evaluate-sessions/references/outcomes.md @@ -26,14 +26,14 @@ Two reasons, both load-bearing: ## Where in the project a context fix is written -You route the fix to a destination in SKILL.md's S9 (lint / AGENTS.md / Expert shard / +You route the fix to a destination in SKILL.md's S9 (lint / AGENTS.md / Expert reference file / nowhere). To find the exact file, read the **project's own** artifacts — not any skill's internals: -- **Expert shard** — open `.claude/skills/expert/references/` in the project and pick the shard - whose subject matches (architecture, verification, patterns, procedural, core-files, - invariants). If none fits and the fact is real, the project's memory updater can place it on - its post-merge pass; your job is to write a clear, correctly-scoped note in the closest shard. +- **Expert reference file** — open `.claude/skills/expert/references/` in the project and pick the + file whose subject matches, by prefix (`how-to-*`, `concept-*`, `pattern-*`, `invariant-*`, + `example-*`). If none fits and the fact is real, the project's memory updater can place it on + its post-merge pass; your job is to write a clear, correctly-scoped note in the closest file. - **AGENTS.md** — the root `AGENTS.md`, or the nested one in the folder the rule is local to. Only if it clears the five-predicate bar (S9); otherwise prefer the Expert. - **A skill defect** — if a *skill's own text* steered the agent wrong, the fix is that skill's diff --git a/skills/human-loop/evaluate-sessions/references/trace-reading.md b/skills/human-loop/evaluate-sessions/references/trace-reading.md index 8dcd4e2..27def1a 100644 --- a/skills/human-loop/evaluate-sessions/references/trace-reading.md +++ b/skills/human-loop/evaluate-sessions/references/trace-reading.md @@ -111,7 +111,7 @@ first: become evals and/or context fixes. - **Inherent difficulty** — the task was just hard; no context change would have helped. Name it and move on. Calling difficulty a "defect" over-fits memory with noise — the - thing `/learn`'s consensus gate and this skill's S4 both guard against. + thing `/learn`'s reconcile justification bar and this skill's S4 both guard against. ## CI / remote degradation From f67913e8f248458a2fef486b6bfbba4f510de324 Mon Sep 17 00:00:00 2001 From: codeisme621 Date: Fri, 3 Jul 2026 21:41:55 -0500 Subject: [PATCH 03/14] simplify /harness-init --- skills/harness/harness-init/SKILL.md | 251 ++++++++++++++++----------- 1 file changed, 152 insertions(+), 99 deletions(-) diff --git a/skills/harness/harness-init/SKILL.md b/skills/harness/harness-init/SKILL.md index 531e018..0c16241 100644 --- a/skills/harness/harness-init/SKILL.md +++ b/skills/harness/harness-init/SKILL.md @@ -1,59 +1,73 @@ --- name: harness-init -description: One-time, guided setup of the local agent-first coding harness — the polling loop, the deterministic dispatcher, its config, the AGENTS.md contract, and the worktree provisioning that makes per-feature worktrees runnable. Use when a developer wants to set up, bootstrap, install, or initialize the coding harness for the first time in a project. +description: One-time setup of the local agent-first coding harness — the polling loop, the deterministic dispatcher, its config, the AGENTS.md contract, and the worktree provisioning that makes per-feature worktrees runnable. Runs as an autonomous installer: writes the artifacts, then opens a feature/harness-init PR for the human to review and merge. Use when a developer wants to set up, bootstrap, install, or initialize the coding harness for the first time in a project. --- # harness-init -Stand up the **local** coding harness for a project, step by step, as a guided -expert session. The developer should finish understanding exactly what was -created and why, with every artifact reviewed and tweakable. +Stand up the **local** coding harness for a project. You are an autonomous +installer: you write the artifacts end-to-end, explain the *significance* of each +as you go, and gather everything onto a `feature/harness-init` PR the human +reviews and merges. The developer should finish understanding what the harness +*is* and why each piece exists — not because you paused for approval at every +line, but because the narration and the PR together make it legible. > Scope: this sets up the **local** harness (Claude Code `/loop` outer runtime). > Server / Claude Agent SDK / OpenSWE modes are future iterations — the > artifacts here are built so they don't have to be torn out to move there. -## How to run this skill +## Operating mode -You are a guide, not a script runner. For **every** step that writes to disk or -runs a git operation: **explain what you're about to do and why → confirm with -the user → do it → show the result → take feedback and adjust.** You have rich -context in `references/` so you never have to guess — read the relevant -reference before each step and narrate from it in plain language. +Run Steps 0–8 end-to-end without stopping for per-step approval. Do not ask the +user to confirm each file write or present diffs for sign-off — **the user +reviews everything in the `feature/harness-init` PR (Step 8).** Your job while +installing is to explain *significance*: for each artifact, say in a sentence or +two what it is, why it exists, and what would break without it. Lead with the +why, then write the file. + +Read first, before you start writing: +- `references/mental-model.md` — so you can explain what the harness *is*. +- `references/invariants-to-preserve.md` — the rules nothing you generate may break. + +Then load other references as each step needs them. Two kinds of artifact: - **Canonical** (drop in verbatim from `assets/`): the dispatcher, the shim - skill, `REVIEW.md`, the env template, the AGENTS.md template skeleton, the - review workflow. Show them, explain them, invite tweaks — but they're the same - everywhere. + skills, `REVIEW.md`, the env template, the AGENTS.md template skeleton, the + review workflow. Same everywhere — install and explain, don't reinvent. - **Software 3.0** (generated by reading the repo): `AGENTS.md`'s filled-in parts, `scripts/local-checks.sh`, and `scripts/bootstrap-worktree.sh`. Scan, - propose, let the user correct. **Never invent a command you didn't see + generate, cite the evidence. **Never invent a command you didn't see evidence for** — ask instead. -Read first, before talking to the user: -- `references/mental-model.md` — so you can explain what the harness *is*. -- `references/invariants-to-preserve.md` — the rules nothing you generate may break. +**Stop-and-confirm points — the only times you interrupt the autonomous install:** -Then load other references as each step needs them. +1. **Step 6 secret-copying** — before writing any `cp` line that touches a + `.env` or credentials file, name the exact files, confirm copy direction + (source → worktree, never reverse, never delete), and get explicit consent. +2. **Step 7 reviewer choice** — recommend the self-hosted default, but confirm + which reviewer path (and, for self-hosted, which auth) the user wants *before* + configuring it. This wires CI and billing, so it's the user's call. +3. **Step 8 the PR merge** — after the PR opens, you stop and wait for the human + to merge before the host worktree and loops can start. + +Everything else runs without interruption. A non-blocking `[warn]` (e.g. an +existing artifact) is noted and handled (re-run mode), not a stop. ## Preconditions The skill runs in the **human's checkout** (their normal working copy), on `main`, with a clean tree and an `origin` remote. The harness will operate in -sibling worktrees, never here (Invariant 6) — but setup writes/commits happen -here because the human is present and consenting. +sibling worktrees, never here (Invariant 6) — but setup writes happen here +because the human is present, and they land on `main` only via the Step 8 PR. --- -## The guided flow +## The install chain ### Step 0 — Preflight -Run `scripts/preflight.sh` from the repo root and walk the user through the -report together. It checks the environment, detects the toolchain, inventories -which inner skills are installed, and flags any harness artifacts that already -exist (re-run detection). +Run `scripts/preflight.sh` from the repo root and interpret the report: - `[MISS]` on environment (no git repo, no `gh`) → resolve before continuing. - `[MISS]` on inner skills → see "Inner skill dependency" below; note them, don't @@ -61,15 +75,15 @@ exist (re-run detection). - `[warn]` on existing artifacts → this is a re-run; diff against what's there rather than clobbering. -Summarize what you found in plain language and confirm the project is ready. +Summarize what you found in plain language and continue. ### Step 1 — Config (`.harness/env`) Read `references/config-options.md`. Derive the author-slug from -`git config user.email`. Explain `MAX_WORKTREES` (default 1) and `WATCH_PATTERN` -(per-dev default) and their tradeoffs; recommend the defaults and only change on -a concrete reason. Write `.harness/env` from `assets/harness-env.template` with -the chosen values. Add the runtime counter files to `.gitignore`: +`git config user.email`. `MAX_WORKTREES` (default 1) and `WATCH_PATTERN` +(per-dev default) carry tradeoffs — use the defaults unless there's a concrete +reason not to. Write `.harness/env` from `assets/harness-env.template` with the +chosen values. Add the runtime counter files to `.gitignore`: ``` .harness/feedback-rounds-* @@ -86,7 +100,7 @@ the chosen values. Add the runtime counter files to `.gitignore`: (The memory loop keeps no local watermark file — the `refs/harness/last-learned` ref on the remote is the watermark — so there is no `last-main-sha` to ignore.) -(Commit `.harness/env` itself; ignore only the counters.) +`.harness/env` itself is committed; only the counters are ignored. ### Step 2 — The dispatcher, the shared lib, and the two tick wrappers @@ -100,33 +114,31 @@ and `chmod +x` the shell scripts: it's sourced, never executed. - `learn-tick.sh` — the **memory-loop** wrapper (the post-merge `/learn` driver). -Then **walk the user through them** — the load-bearing properties of the dispatcher -(including the HUMAN_REVIEW convergence exit — the reviewer's `REVIEW_CLEAN_MARKER` -comment hands the PR to the human for `/evaluate-pr`), the section map, the -**bootstrap hook** (the project-owned worktree provisioning; explain why it's there), -and the **`harness-tick.sh` wrapper**: the build loop targets the wrapper, which -force-syncs the host worktree to a clean `origin/main` and *then* `exec`s the -(HEAD-agnostic) dispatcher. Explain why the sync lives in the wrapper, not the -dispatcher: the dispatcher must never reset its own running file, and this is how -loop-infrastructure updates merged to main (dispatcher, `.harness/env`) reach the -loop — feature *pipeline* skills ride the PRD branch and need no sync. +Explain the load-bearing properties as you install them — the dispatcher's +HUMAN_REVIEW convergence exit (the reviewer's `REVIEW_CLEAN_MARKER` comment hands +the PR to the human for `/evaluate-pr`), the **bootstrap hook** (the project-owned +worktree provisioning), and the **`harness-tick.sh` wrapper**: the build loop +targets the wrapper, which force-syncs the host worktree to a clean `origin/main` +and *then* `exec`s the (HEAD-agnostic) dispatcher. The sync lives in the wrapper, +not the dispatcher, because the dispatcher must never reset its own running file — +and this is how loop-infrastructure updates merged to main (dispatcher, +`.harness/env`) reach the loop; feature *pipeline* skills ride the PRD branch and +need no sync. Then explain **the memory loop is a separate loop** (`references/dispatcher-explained.md` → "The memory loop"): `/learn` is NOT a dispatcher step. `learn-tick.sh` runs it under its own `/loop … /learn-loop`, in its own dedicated `../-harness-learn` worktree, gated by the `refs/harness/last-learned` watermark ref and paused while a `learn/` -PR is open. The two loops never block each other and coordinate only through git. Offer -the common tweaks (PRD-runner stuck cap, feedback round cap, extra pipeline steps, the -memory-loop interval). Do not let them break the "what NOT to do" list. +PR is open. The two loops never block each other and coordinate only through git. ### Step 3 — The shim skills Copy **both** shims: `assets/poll-and-dispatch-SKILL.md` → `.claude/skills/poll-and-dispatch/SKILL.md` and `assets/learn-loop-SKILL.md` → -`.claude/skills/learn-loop/SKILL.md`. Explain the `/loop` gotcha: an outer session must -never do real work — each shim only calls its tick script (`harness-tick.sh` / -`learn-tick.sh`), and all real work happens in fresh `claude -p` subprocesses. One -paragraph; then move on. +`.claude/skills/learn-loop/SKILL.md`. The significance: an outer `/loop` session +must never do real work — each shim only calls its tick script (`harness-tick.sh` +/ `learn-tick.sh`), and all real work happens in fresh `claude -p` subprocesses, +so no step inherits another's polluted window. ### Step 4 — `AGENTS.md` (Software 3.0) @@ -134,18 +146,17 @@ Read `references/agents-md-guidance.md` and `references/project-discovery.md`. Scan the repo, fill `assets/AGENTS.md.template`'s bracketed parts (project name, the verification-layer tooling), keep the rest verbatim. AGENTS.md is the neutral, eagerly-loaded contract — a map that points into the Expert, not an encyclopedia; -keep it tight (the freshness lint caps the root at ~150 lines). Present it as a -diff against the template, citing the scan finding behind each filled-in line. Let -the user edit before committing. Tell them the Expert section is intentional even -though the Expert is empty until their first merge. +keep it tight (the freshness lint caps the root at ~150 lines). Cite the scan +finding behind each filled-in line as you write it. The Expert section is +intentional even though the Expert is empty until the first `/learn`. ### Step 5 — `scripts/local-checks.sh` (optional, Software 3.0) The deterministic gate the dispatcher runs before opening a PR (two-strike retry: `local-checks.sh fix` → `/fix-local-checks` → STUCK). It's the cheapest place to catch correctness issues — left of the reviewer and CI. **Read -`references/local-checks-design.md` first** and narrate the *why* to the user; they -own and tune this script. Detect commands via `references/project-discovery.md`. +`references/local-checks-design.md` first** and narrate the *why*; the user owns +and tunes this script. Detect commands via `references/project-discovery.md`. It has two responsibilities (the reference details both): @@ -155,17 +166,18 @@ It has two responsibilities (the reference details both): project already defines; call existing pre-commit hooks rather than duplicating. - **Propose custom correctness lints** from the codebase as-is (snapshot discovery) — observed existing invariants + surface-scoped best-practice lints, behind the - five guards in the reference. **Propose; the user disposes.** + five guards in the reference. The gate proves **correctness, not coverage** — block only correctness/structural, *warn* on legibility/observability, and don't add checks for volume (mutation testing is a sensor, not here). The **skip rule** is load-bearing: an agent may never add a test-skip marker; a legitimate skip is the human's call at STUCK. -If the user doesn't want this gate, skip it — the dispatcher treats the script as -absent and works fine. **If you do generate it,** mind the Step 6 dependency: -because it runs typecheck and tests, the worktree must be fully runnable, so -`bootstrap-worktree.sh` has to be solid or these legs fail for the wrong reason. +If the project clearly has no deterministic checks to wire, skip this — the +dispatcher treats the script as absent and works fine. **If you do generate it,** +mind the Step 6 dependency: because it runs typecheck and tests, the worktree must +be fully runnable, so `bootstrap-worktree.sh` has to be solid or these legs fail +for the wrong reason. ### Step 6 — `scripts/bootstrap-worktree.sh` (Software 3.0) @@ -175,18 +187,23 @@ install dependencies, run codegen. Discover the setup from README/CI/manifests (project-discovery.md); if discovery is thin, **ask the user how they set the project up on a fresh machine**. -**Flag the secret-copying loudly.** This is the one place the harness touches -sensitive files: name exactly which files get copied and from where, confirm the -destination is a same-machine `*-harness*` worktree, confirm copy direction is -always source→worktree and nothing is deleted, and get explicit consent. If the -project has no gitignored secrets, skip that part and say so. Generate an -idempotent, non-interactive, well-commented script. - -### Step 7 — Reviewer (optional) - -Read `references/reviewer-options.md`. Present the three paths (self-hosted via -`claude-code-action` = recommended default; managed Code Review; none). Explain -the tradeoffs and that switching later is cheap (one workflow file). Then: +**Flag the secret-copying loudly — stop-and-confirm point 1.** This is the one place the +harness touches sensitive files: name exactly which files get copied and from +where, confirm the destination is a same-machine `*-harness*` worktree, confirm +copy direction is always source→worktree and nothing is deleted, and get explicit +consent before writing those lines. If the project has no gitignored secrets, skip +that part and say so. Generate an idempotent, non-interactive, well-commented +script. + +### Step 7 — Reviewer (stop-and-confirm point 2) + +Read `references/reviewer-options.md`. There are three paths (self-hosted via +`claude-code-action` = recommended default; managed Code Review; none); switching +later is cheap (one workflow file). **This step is not autonomous: present the +three paths, recommend self-hosted, and confirm with the user which path they +want — and, for self-hosted, which auth — before configuring anything.** It wires +CI workflow files and a billing choice, so it's the user's decision. Once they +choose, install that path: - **Self-hosted:** copy `assets/REVIEW.md` to repo root + `assets/workflows/claude-review.yml` to `.github/workflows/`, and: 1. **Pick auth with the user.** The template ships with `claude_code_oauth_token` @@ -215,31 +232,63 @@ the tradeoffs and that switching later is cheap (one workflow file). Then: **Convergence marker (both reviewer paths).** `REVIEW.md` instructs the reviewer to post a PR comment containing `HARNESS_REVIEW_CLEAN` once it has no Important findings left. That marker is how the dispatcher knows the review loop converged and hands the -PR to the human for `/evaluate-pr` — it's a single deterministic signal, -the same for managed and self-hosted. The token is configurable via -`REVIEW_CLEAN_MARKER` in `.harness/env` (must match what `REVIEW.md` tells the -reviewer to post). If the reviewer never posts it, the feedback loop reaches -`FEEDBACK_CAP` and STUCKs instead — a clean PR the human merges. - -### Step 8 — Host worktree + provision - -Explain the three-checkout model (see `references/mental-model.md`): the -human's checkout stays on `main`; the -harness **host** worktree is a sibling that stays **detached at `origin/main`** -(re-synced every tick by `harness-tick.sh`); per-feature work happens in -*ephemeral* `../-harness-` worktrees the dispatcher creates and -tears down. Create the host worktree **detached** — git won't let two worktrees -check out `main` at once, and the human's checkout already holds it: +PR to the human for `/evaluate-pr` — a single deterministic signal, the same for +managed and self-hosted. The token is configurable via `REVIEW_CLEAN_MARKER` in +`.harness/env` (must match what `REVIEW.md` tells the reviewer to post). If the +reviewer never posts it, the feedback loop reaches `FEEDBACK_CAP` and STUCKs +instead — a clean PR the human merges. + +### Step 8 — Commit on `feature/harness-init`, push, open PR, wait for merge + +**Hard rule: never commit harness setup artifacts directly to `main`.** Everything +from Steps 1–7 lands on `feature/harness-init` and reaches `main` only via a merged +PR. This is the review checkpoint — the whole install in one diff. + +Create the branch, stage the artifacts, commit, push, and open the PR: + +``` +git checkout -b feature/harness-init +git add .harness/env .gitignore scripts/ AGENTS.md REVIEW.md .github/ +git commit -m "harness: initial setup via harness-init" +git push -u origin feature/harness-init +gh pr create --base main --head feature/harness-init \ + --title "harness: initial setup" --fill +``` + +Walk the user through the PR — what's in it, why each piece is there — then **stop +and ask them to merge it before continuing (stop-and-confirm point 3).** + +**Why merge first?** Two load-bearing reasons: +- Step 9 creates the host worktree with `git worktree add --detach … origin/main`. + Until the merge lands, `origin/main` has none of the harness scripts, so the + worktree would be empty of `harness-tick.sh` and `poll-and-dispatch.sh`. +- `harness-tick.sh` force-resyncs to `origin/main` on every tick. Even if you + bootstrapped from the feature branch directly, the first tick would wipe it back + to a `main` that has no scripts. + +Once the user confirms the PR is merged and their local `main` is current +(`git fetch && git pull`), continue to Step 9. + +### Step 9 — Host worktree + provision + +Explain the three-checkout model (see `references/mental-model.md`): the human's +checkout stays on `main`; the harness **host** worktree is a sibling that stays +**detached at `origin/main`** (re-synced every tick by `harness-tick.sh`); +per-feature work happens in *ephemeral* `../-harness-` worktrees the +dispatcher creates and tears down. Create the host worktree **detached** — git +won't let two worktrees check out `main` at once, and the human's checkout already +holds it: ``` git worktree add --detach ../-harness origin/main ``` -Then run `scripts/bootstrap-worktree.sh ../-harness` to provision it. This +Then provision it with `scripts/bootstrap-worktree.sh ../-harness`. This **doubles as validation of the bootstrap script** — if the host worktree is -runnable afterward, the script works. Fix and re-run if not. +runnable afterward, the script works. Verify runnability before continuing; fix +and re-run if not. -### Step 9 — Dry-run the tick +### Step 10 — Dry-run the tick From the **harness host worktree** (`../-harness`), run `./scripts/harness-tick.sh` once. It force-syncs the worktree to `origin/main` @@ -251,15 +300,13 @@ Then run `./scripts/learn-tick.sh` once. On a fresh repo (Expert not yet built, merges since the watermark) it creates and bootstraps the `../-harness-learn` worktree, finds no new range, and exits — proving the memory-loop wiring. Walk through both outputs with the user. If anything errors, debug before starting the -loops. (Note: with no `origin` yet, the fetch fails fast — that's expected until the -remote exists.) +loops. -### Step 10 — Commit, then start the loop +### Step 11 — Start the loops -Commit the setup artifacts on `main` (or on a setup branch for the user to merge -— ask). Then explain how to start the harness. It runs as **two independent loops**, -each in its own long-lived Claude Code session pinned to the harness worktree — the -build loop (features) and the memory loop (`/learn`). They never block each other: +Explain how to start the harness. It runs as **two independent loops**, each in its +own long-lived Claude Code session pinned to the harness worktree — the build loop +(features) and the memory loop (`/learn`). They never block each other: ``` cd ../-harness @@ -304,15 +351,18 @@ both **outer** loops; it does not author these. Preflight reports which are installed. If some are missing, set up the harness anyway and tell the user clearly which skills must be installed from the catalog before the chain runs end to end — the harness will dispatch to them the moment they exist. -(`/learn` is the memory skill under `.claude/skills/memory/`; the project's -Expert is born from the first `/learn`.) +(The project's Expert is born from the first `/learn`, written directly under +`.claude/skills/expert/`.) ## Re-running Safe to re-run. Preflight flags existing artifacts. For canonical files, diff and offer to update. For generated files (`AGENTS.md`, `local-checks.sh`, `bootstrap-worktree.sh`), re-scan and show a diff rather than overwriting blind. -Never delete the human's host worktree or secrets on a re-run. +Never delete the human's host worktree or secrets on a re-run. If +`feature/harness-init` already exists from a prior run, detect it, diff the +existing branch against the current state, and update that branch rather than +creating a fresh one. ## Hard rules (from invariants-to-preserve.md) @@ -322,3 +372,6 @@ Never delete the human's host worktree or secrets on a re-run. - Never generate a "go backward" / sentinel-deleting step (Invariant 9). - `bootstrap-worktree.sh` copies secrets source→worktree only, never deletes, never the reverse (Invariant 6). +- Never commit harness setup artifacts directly to `main`. All harness-init + artifacts land on `feature/harness-init` and reach `main` only via a merged + PR. The host worktree and the loops cannot start until that merge (Step 8). From 59347d59be48dc1a11f099a9ff2015b0831e25c4 Mon Sep 17 00:00:00 2001 From: codeisme621 Date: Fri, 3 Jul 2026 21:58:11 -0500 Subject: [PATCH 04/14] simplify impl mainspec --- README.md | 8 +- docs/2-spec-driven-development.md | 23 +- skills/sdd/implement-mainspec/SKILL.md | 467 ++---------------- .../references/error-handling.md | 61 +-- .../references/release-strategy.md | 49 -- .../references/subagent-prompt-template.md | 68 +-- .../scripts/compute_tiers.py | 253 ---------- .../scripts/tests/test_tier_computation.py | 332 ------------- subagents/slice-implementer.md | 2 +- 9 files changed, 78 insertions(+), 1185 deletions(-) delete mode 100644 skills/sdd/implement-mainspec/references/release-strategy.md delete mode 100644 skills/sdd/implement-mainspec/scripts/compute_tiers.py delete mode 100644 skills/sdd/implement-mainspec/scripts/tests/test_tier_computation.py diff --git a/README.md b/README.md index 2147d18..73e4806 100644 --- a/README.md +++ b/README.md @@ -55,9 +55,9 @@ define the knowledge once, and it flows automatically through every phase: (3/3 = very high, 2/3 = high) turning agreement into a confidence signal. Impactful findings are applied in place. 3. **Implementation** ([`/implement-mainspec`](./skills/sdd/implement-mainspec/SKILL.md)) — - slices implemented in dependency order, sequential or auto-parallelized across - git worktrees. Each slice is verified by its unit tests, then a **Reflect** step - (below) feeds what the implementer learned back into the expert. + slices implemented in dependency order, one at a time on the feature branch. + Each slice is verified by its unit tests, then a **Reflect** step (below) feeds + what the implementer learned back into the expert. **Composable, not hardcoded.** Multiple experts activate for one feature — a React expert and a DynamoDB expert both contribute on a full-stack change. Add or @@ -267,7 +267,7 @@ Run from your target project directory. Copies agent definitions (e.g. | **1 · SDD** | `/expert-sdd-creator` | Create a domain expert from your docs | | | `/spec-planning` | Idea → mainspec + temporal slices | | | `/spec-validate` | Multi-agent consensus + expert review | -| | `/implement-slice`, `/implement-mainspec` | Implement slices with unit tests + Reflect, sequential or parallel | +| | `/implement-slice`, `/implement-mainspec` | Implement slices sequentially with unit tests + Reflect | | **2 · Harness** | `/harness-init` | Guided setup of the local harness | | | `/fix-local-checks` | Honest fixes for a failing pre-PR gate | | | `/address-feedback` | Triage and answer reviewer findings | diff --git a/docs/2-spec-driven-development.md b/docs/2-spec-driven-development.md index b745b8c..b0ce60c 100644 --- a/docs/2-spec-driven-development.md +++ b/docs/2-spec-driven-development.md @@ -109,10 +109,9 @@ for future ones. That ordering does two jobs at once. For the implementer, it's progressive disclosure made structural: the agent is fed **only the current slice**, never the whole feature, so its window stays small and focused. For the orchestrator, -the dependencies form a DAG — and a DAG can be parallelized. Every mainspec -carries a **Slice Dependency Map** (a table plus a Mermaid graph), and -[`compute_tiers.py`](../skills/sdd/implement-mainspec/scripts/compute_tiers.py) -topologically sorts it to find which slices can run concurrently. +the dependencies define the execution order. Every mainspec carries a **Slice +Dependency Map** (a table plus a Mermaid graph), which the orchestrator reads to +implement slices in dependency order, one at a time. ## Validation — consensus before code @@ -151,17 +150,13 @@ two halves of the same module. The bar is deliberately high: most slices reflect nothing. [`/implement-mainspec`](../skills/sdd/implement-mainspec/SKILL.md) -orchestrates the whole feature and auto-detects how to run it: +orchestrates the whole feature: it reads the Slice Dependency Map and delegates +each slice, in dependency order, to a focused `slice-implementer` subagent — +committing each to the feature branch as it lands. One slice at a time keeps the +orchestrator's window lean and every commit reviewable. -- **Sequential** (≤3 slices) — one slice at a time, committed directly to the - branch. Simple and linear. -- **Parallel** (>3 slices) — the DAG from `compute_tiers.py` drives tiered - execution: Tier 0 (foundation) first, then later tiers fan out across git - worktrees with a focused `slice-implementer` subagent per slice (up to 7 - concurrent), gating each tier before the next. - -Either way, the feedback loop runs **per slice**, not just at the end — the agent -knows whether it's on track as it goes, not after. +The feedback loop runs **per slice**, not just at the end — the agent knows +whether it's on track as it goes, not after. ## What you have at the end of Layer 1 diff --git a/skills/sdd/implement-mainspec/SKILL.md b/skills/sdd/implement-mainspec/SKILL.md index 4bbedfa..7324648 100644 --- a/skills/sdd/implement-mainspec/SKILL.md +++ b/skills/sdd/implement-mainspec/SKILL.md @@ -1,53 +1,42 @@ --- name: implement-mainspec -description: Implements a mainspec end-to-end by auto-detecting mode. Sequential mode (≤3 slices) commits slices in order on the current `feature/` branch. Parallel mode (>3 slices) uses dependency-aware tiered execution with per-slice worktrees, branches, PRs, and auto-merge into the feature branch. Agent-first — invoked headless by the harness dispatcher with the feature slug as its single argument. No human-in-the-loop, no approval gates. +description: Implements a mainspec end-to-end by delegating each slice to a `slice-implementer` subagent in dependency order, committing to `feature/` directly. Agent-first — invoked headless by the harness dispatcher with the feature slug. No human-in-the-loop, no approval gates. --- # Implement Mainspec -Implements all slices from a mainspec in dependency order. Auto-detects **sequential** (≤3 slices) or **parallel** (>3 slices) mode based on tier computation. Agent-first: invoked headless by the harness dispatcher, runs end-to-end with no approval gates, exits. +Implements all slices from a mainspec in dependency order, sequentially. Agent-first: invoked headless by the harness dispatcher, runs end-to-end with no approval gates, exits. ## Invocation Contract -**Invoked by the dispatcher as:** `claude -p "/implement-mainspec "`, run from inside the feature worktree (the dispatcher `cd`s into it — there is no print-mode `--cwd` flag). +**Invoked by the dispatcher as:** `claude -p "/implement-mainspec "`, run from inside the feature worktree (the dispatcher `cd`s into it). **Single argument:** `` — kebab-case feature slug. The mainspec path is `specs//mainspec.md` relative to cwd. **Inputs read from disk (paths relative to cwd):** - `specs//mainspec.md` - `specs//slices/*.md` -- Current `feature/` branch state (worktree HEAD). +- Current `feature/` branch state. **Outputs to disk / remote:** -- Per-slice branches `slice/-` pushed to origin (**not deleted after merge** — they remain as archaeological evidence so the eventual `feature/ → main` PR review can trace which commits belong to which slice). -- Per-slice PRs merged into `feature/` with `gh pr merge --merge` (preserves slice commits + a merge commit). -- All implementation code committed and pushed on `feature/`. +- All implementation code committed and pushed on `feature/`, one commit per slice. -**No sentinel.** The dispatcher's success signal for this step is `./prds//run-prd-test.sh` exits 0, verified externally. The PRD test is encoded into a slice's Signal by spec-planning, so completing all slices implies the PRD test passes. We do not write a sentinel file — the *dispatcher* records the green result in `specs//.prd-passed` once the runner first exits 0 (so a possibly-LLM-judge runner isn't re-run every tick); this skill neither writes nor reads that file. +**No sentinel.** The dispatcher's success signal for this step is `./prds//run-prd-test.sh` exits 0, verified externally. The final slice's Success Criteria encodes this into a slice so completing all slices implies the PRD test passes. We do not write a sentinel file — the *dispatcher* records the green result in `specs//.prd-passed` once the runner first exits 0; this skill neither writes nor reads that file. **Idempotency:** -- On every invocation, inspect `feature/` git history. Determine which slices are already merged (look for merge commits like `Merge slice/-` or branches whose commits match slice scope). -- Compute the remaining slices via the DAG (`compute_tiers.py`) minus the already-merged set. +- On every invocation, inspect `feature/` git history. Determine which slices are already committed (look for commits like `Implement slice : `). +- The orchestrator reads the mainspec's Slice Dependency Map inline to plan its execution order. - Work only on remaining slices. -- If all slices appear merged, exit cleanly. The dispatcher will re-verify the PRD test externally. +- If all slices appear committed, exit cleanly. The dispatcher will re-verify the PRD test externally. -**No approval gates anywhere.** No `AskUserQuestion` for plan approval, default-branch warning, tier review, retry decisions, or branch-state ambiguity. Every decision is deterministic or deferred to the next dispatcher tick. +**No approval gates anywhere.** No `AskUserQuestion` for plan approval, default-branch warning, or any other decision. Every decision is deterministic or deferred to the next dispatcher tick. ## Workflow Overview ``` -Phase 0: Detection — Run compute_tiers.py, check total_slices to select mode -Phase 1: Parse & Resume — Read mainspec, parse DAG, inspect feature/ for already-merged slices - ---- SEQUENTIAL MODE (≤3 slices) --- -Phase 2: Implement — Delegate each remaining slice to slice-implementer subagent (sequential, foreground). Orchestrator handles git directly on feature/. +Phase 1: Parse & Resume — Read mainspec Slice Dependency Map, determine execution order, inspect feature/ for already-committed slices +Phase 2: Implement — Delegate each remaining slice to slice-implementer subagent (foreground). Orchestrator handles git directly on feature/. Phase 3: Log — Log final status of this invocation to stdout for observability - ---- PARALLEL MODE (>3 slices) --- -Phase 2: Tier 0 — Delegate foundation slices to slice-implementer subagents (sequential, foreground). Orchestrator handles git directly on feature/. -Phase 3: Parallel Tiers — For each subsequent tier: create worktrees, spawn slice-implementer subagents (background), orchestrator handles git after completion. -Phase 4: Auto-Merge — Create PRs and auto-merge into feature/ with `gh pr merge --merge`. Branches are NOT deleted on merge. -Phase 5: Log — Log final status of this invocation to stdout for observability ``` ## Pre-conditions @@ -57,106 +46,54 @@ The dispatcher guarantees a clean worktree on `feature/` before invokin 1. **Git repository** — `git rev-parse --git-dir` succeeds. If not, exit non-zero. 2. **Current branch matches `feature/`** — must match the argument exactly. If not, exit. (Never create the feature branch; the dispatcher's atomic rename from `prd//` did that.) 3. **Clean working tree** — `git status --porcelain` empty. If not, exit (the dispatcher's wipe should guarantee this; if it trips, something upstream is wrong). -4. **Remote configured** — `git remote get-url origin` succeeds. If not, exit. Parallel mode requires remote. -5. **Worktree gitignore** — verify `.claude/worktrees/` is in `.gitignore`. Auto-append if missing (idempotent; no prompt). - -## Phase 0: Mode Detection - -Run the tier computation script and select the execution mode deterministically: - -``` -1. Run: python3 .claude/skills/implement-mainspec/scripts/compute_tiers.py specs//mainspec.md -2. Parse the JSON output which includes: - - mainspec_name, feature_branch - - tiers: array of { tier: N, slices: [{ number, name, file }] } - - file: absolute path to the slice file (can be used directly by subagents) - - total_slices, max_parallel -3. Mode detection (no override, no prompt): - - total_slices ≤ 3 → SEQUENTIAL MODE - - total_slices > 3 → PARALLEL MODE -4. Log to stdout: "Detected slices → mode" for observability. -``` +4. **Remote configured** — `git remote get-url origin` succeeds. If not, exit. ## Phase 1: Parse & Resume -### DAG Parsing - -`compute_tiers.py` parses the mainspec's "Slice Dependency Map" table: +### Slice Ordering -| Field | Source | Example | -|-------|--------|---------| -| Slice number | First column, before ` — ` | `3.1` | -| Slice name | First column, after ` — ` | `SVG Path Animation Utilities` | -| Dependencies | "Depends On" column | `3.1` or `—` (none) | -| Blocks | "Blocks" column | `3.2, 3.3, 3.4, 3.5` or `—` (none) | -| Slice file path | From compute_tiers.py output | absolute path to slice file | +Read the mainspec's "Slice Dependency Map" table directly. For each slice, note its number, name, and `Depends On` list. Use that understanding to plan the execution order — slices whose dependencies are already committed (or have no dependencies) can run next; slices with outstanding dependencies wait. -The script handles topological sort and tier assignment via the algorithm: +Reference the slice file path convention: `specs//slices/-.md`. -``` -1. Start with all slices. remaining = all slices. -2. Tier 0 = slices with no dependencies (Depends On = "—" or "Nothing") -3. Remove Tier 0 from remaining -4. Tier N = slices in remaining whose ALL dependencies are in Tiers 0..N-1 -5. Remove Tier N from remaining -6. Repeat until remaining is empty -7. If remaining is not empty and no progress was made → circular dependency error -``` +### Resume Detection (Idempotency) -### Resume detection (idempotency) - -Before implementing anything, inspect what's already merged on `feature/`: +Before implementing anything, inspect what's already committed on `feature/`: ``` 1. git fetch origin -2. For each slice in the mainspec DAG: - - Check whether a merge commit referencing `slice/-` exists in - `git log feature/` (e.g., `git log --merges --grep "slice/-"`). - - If yes, mark slice as ALREADY-MERGED. Skip it. +2. For each slice in the mainspec: + - Check whether a commit referencing "Implement slice :" exists in + git log feature/ (e.g., git log --oneline --grep "Implement slice :"). + - If yes, mark slice as ALREADY-COMMITTED. Skip it. - Otherwise, mark slice as REMAINING. -3. If all slices are ALREADY-MERGED, log "all slices merged, nothing to do" and exit cleanly. -4. Otherwise, proceed with REMAINING slices in their original tier assignments. +3. If all slices are ALREADY-COMMITTED, log "all slices committed, nothing to do" and exit cleanly. +4. Otherwise, proceed with REMAINING slices in their dependency order. ``` -### Plan logging (no approval) - -Log the computed plan to stdout for observability — what mode, which tiers, which slices are remaining vs. already-merged. **No approval gate, no `AskUserQuestion`.** Proceed directly to Phase 2. +### Plan Logging (No Approval) -**Sequential mode log format:** +Log the computed plan to stdout for observability — which slices are remaining vs. already-committed. **No approval gate, no `AskUserQuestion`.** Proceed directly to Phase 2. ``` ## Execution Plan: -Mode: Sequential -Total slices: N (already-merged: M, remaining: K) +Total slices: N (already-committed: M, remaining: K) Remaining order: 1. Slice X.Y: 2. Slice X.Y: ``` -**Parallel mode log format:** - -``` -## Execution Plan: -Mode: Parallel -Feature branch: feature/ -Total slices: N (already-merged: M, remaining: K) -Total tiers: T (remaining tiers to process: T') -Tier 0 (Foundation): X.Y , X.Y -Tier 1 (Parallel — N subagents): X.Y , X.Y -Tier 2 (Parallel — N subagents): X.Y -``` +## Phase 2: Implementation -## Phase 2: Sequential Implementation +The preconditions already guaranteed we are on `feature/`, so we commit directly to it. No default-branch warning, no approval prompt. -**Applies only to SEQUENTIAL MODE (≤3 slices).** The preconditions section already guaranteed we are on `feature/`, so we commit directly to it. No default-branch warning, no approval prompt. +For each **REMAINING** slice in dependency order (skipping already-committed ones from Phase 1): -For each **REMAINING** slice in dependency order (skipping already-merged ones from Phase 1): - -1. Create TODO list — One item per slice with sub-items for: Implement, Signal Validation, Unit Tests. +1. Create TODO list — One item per slice. 2. Mark slice in_progress. 3. Delegate to a `slice-implementer` subagent (foreground, NOT background): - Use `subagent_type: "slice-implementer"` and `mode: "bypassPermissions"`. - - Use the prompt template from `references/subagent-prompt-template.md` (Sequential Mode section). The template passes `max_signal_iterations: 3` to bound the inner signal-fix loop. + - Use the prompt template from `references/subagent-prompt-template.md`. - Set working directory to the repo root. - Wait for subagent to complete. 4. After subagent completes successfully: @@ -166,345 +103,50 @@ For each **REMAINING** slice in dependency order (skipping already-merged ones f - Orchestrator runs `git push origin feature/`. 5. If subagent reports FAILURE: - Log the failure (slice number, error text) to stdout. - - Commit any safe partial work attributable to a completed earlier slice (we should never have partial state at this point since each slice's commits happen synchronously after subagent success — but if `git status` shows changes, they should not be committed). + - Do not commit any partial state. - Exit. The dispatcher will re-fire on the next tick; idempotency in Phase 1 will skip the already-completed slices and retry this one. 6. Mark slice complete. After all remaining slices: proceed to Phase 3 (Log). -## Phases 2–5: Parallel Implementation - -**Applies only to PARALLEL MODE (>3 slices).** See below for detailed instructions: - -- **Phase 2 (Tier 0)** — See "Tier 0: Foundation Slices" section. -- **Phase 3 (Parallel Tiers)** — See "Parallel Tier Execution" section. -- **Phase 4 (Auto-Merge)** — See "Tier Auto-Merge" section. -- **Phase 5 (Log)** — Stdout log only. - -## Feature Branch Verification & Git Strategy - -**Applies only to PARALLEL MODE.** The dispatcher's atomic rename already created `feature/` before this skill ran. We verify and proceed; we never create the feature branch. - -``` -1. Verify HEAD branch == feature/: - actual="$(git rev-parse --abbrev-ref HEAD)" - [[ "${actual}" == "feature/" ]] || exit 1 -2. Verify the branch tracks origin: - git rev-parse --abbrev-ref --symbolic-full-name @{u} >/dev/null 2>&1 || git push -u origin feature/ -``` - -**Naming conventions:** -- Feature branch: `feature/` (e.g., `feature/svg-and-charts`). -- Slice branch: `slice/-` (e.g., `slice/3.3-barchart`). -- Worktree path: `.claude/worktrees//slice--`. - -**Spec file access:** Spec files are referenced by absolute path (resolved from `compute_tiers.py` output). Subagents read specs from the original location, not from their worktree. - -**Git state recovery (deterministic, no prompts):** -- Feature branch exists locally and matches origin: proceed. -- Feature branch exists but is behind origin: `git pull --ff-only origin feature/` before any tier work. -- Slice branch already exists on origin: this means a prior `/implement-mainspec` tick was interrupted. Check whether the corresponding PR is merged via `gh pr view slice/- --json state -q .state`: - - State `MERGED` → slice is done; skip it. - - State `OPEN` → PR was created but not merged; auto-merge it as part of Phase 4. - - No PR found → branch has commits but no PR; create the PR in Phase 4 and proceed. - - Branch exists with no commits past `feature/` HEAD → unusable, but harmless; recreate the worktree on top. - -## Tier 0: Foundation Slices - -**Applies only to PARALLEL MODE.** Execute on `feature/` directly. - -Tier 0 slices are delegated to `slice-implementer` subagents sequentially (one at a time, foreground). The orchestrator handles all git operations. - -For each REMAINING Tier 0 slice (in dependency order): - -1. Spawn a `slice-implementer` subagent (foreground, NOT background): - - Use `subagent_type: "slice-implementer"` and `mode: "bypassPermissions"`. - - Use the prompt template from `references/subagent-prompt-template.md` (Tier 0 section). - - Set working directory to the repo root (subagent works on feature branch directly). - - Wait for subagent to complete. -2. After subagent completes successfully: - - Orchestrator runs `git status` to detect changed files. - - Orchestrator runs `git add ` (only files the subagent created/modified). - - Orchestrator runs `git commit -m "Implement slice : "`. - - Orchestrator runs `git push origin feature/`. -3. If subagent reports FAILURE: - - Log the failure. - - Do not commit any subagent partial state. - - Exit. Dispatcher will re-fire; idempotency will skip merged work and retry this slice. -4. Proceed to next Tier 0 slice (if multiple foundation slices). - -Tier 0 slices are committed directly to `feature/` — no PRs. This is the foundation that all subsequent tiers depend on. - -## Worktree Management - -**Applies only to PARALLEL MODE.** Create worktrees before spawning subagents for each tier. - -**Critical:** Do NOT use `isolation: "worktree"` from the Agent tool — it branches from the remote default branch and won't have Tier 0 code. - -**Preflight — bootstrap availability.** Before creating any worktrees, check for `scripts/bootstrap-worktree.sh`. If it is **not** an executable file, emit a loud warning to stdout — e.g. `WARN: no executable scripts/bootstrap-worktree.sh found; slice worktrees will lack deps/.env/codegen, so signals and unit tests may fail. Continuing anyway.` — then proceed. Do **not** halt: a missing bootstrap script is a warning, not a precondition. When the script IS present, each worktree is bootstrapped right after creation (see below). - -### Creating Worktrees - -For each REMAINING slice in the current tier (skip slices whose PR is already merged): - -```bash -# Derive names from compute_tiers.py output -worktree_name="slice--" -branch_name="slice/-" -worktree_path=".claude/worktrees//${worktree_name}" - -# Create worktree branching FROM the feature branch. -# If branch already exists locally or on origin, attach without -b. -if git show-ref --verify --quiet "refs/heads/${branch_name}" \ - || git show-ref --verify --quiet "refs/remotes/origin/${branch_name}"; then - git worktree add "${worktree_path}" "${branch_name}" -else - git worktree add "${worktree_path}" -b "${branch_name}" feature/ -fi - -# Record the absolute worktree path for the subagent prompt -abs_worktree_path="$(realpath ${worktree_path})" - -# Make the fresh worktree runnable: a bare worktree has no gitignored files -# (node_modules, .env, generated code), so slice signals and unit tests would fail -# for reasons unrelated to the feature. Mirrors the dispatcher's bootstrap hook. -# Idempotent + non-interactive; a failure here is logged but does not stop the slice. -if [[ -x scripts/bootstrap-worktree.sh ]]; then - ./scripts/bootstrap-worktree.sh "${abs_worktree_path}" || \ - echo "WARN: bootstrap-worktree.sh failed for ${abs_worktree_path} — signals/tests may fail" >&2 -fi -``` - -### Cleaning Up Worktrees - -After PRs for a tier have been merged (or on a controlled exit): - -``` -1. For each worktree: git worktree remove -2. If removal fails (uncommitted changes): log the failure and exit. - The dispatcher's next tick will wipe state and re-derive what to do. -3. After all tiers complete: git worktree prune -``` - -## Parallel Tier Execution - -**Applies only to PARALLEL MODE.** Execute for each REMAINING tier after Tier 0. - -### 3a. Create Worktrees - -Create worktrees for all REMAINING slices in this tier per the Worktree Management section above. - -### 3b. Spawn Subagents - -Read `references/subagent-prompt-template.md` for the full prompt template. - -Spawn one background subagent per slice: -- Use the Agent tool with `run_in_background: true`. -- Use `subagent_type: "slice-implementer"` and `mode: "bypassPermissions"`. -- Do NOT use `isolation: "worktree"` (worktree already created in 3a). -- Spawn all subagents for this tier in a SINGLE message (maximizes parallelism). -- Capture the agent_id / task_id for each subagent. -- The prompt template includes `max_signal_iterations: 3` to bound the inner signal-fix loop. - -**Batching:** If a tier has more than 7 slices, split into batches of up to 7. Spawn batch 1, wait for all to complete, then spawn batch 2. +## Phase 3: Stdout Log (Observability Only) -### 3c. Wait for Completion - -- Subagents will notify when done (automatic delivery). -- Alternatively, use `TaskOutput(task_id=, block=true)` per subagent. -- Collect results: success/failure per slice. - -### 3d. Git Operations (Orchestrator) - -After all subagents for the tier complete, the orchestrator handles git for each worktree of a successful slice: - -``` -For each successful slice in the tier: -1. cd -2. git status (detect changed files) -3. git add (only files the subagent created/modified, NOT git add -A) -4. git commit -m "Implement slice : " -5. git push -u origin -``` - -### 3e. Handle Failures - -- If a subagent fails, log the slice number and error details to stdout. -- Other subagents in the same tier are NOT affected — they finish their work. -- The failed slice will NOT get a PR in Phase 4. -- Read `references/error-handling.md` for detailed recovery procedures. - -## Tier Auto-Merge - -**Applies only to PARALLEL MODE.** Execute after each tier's subagents complete and orchestrator git operations finish. There is no review gate, no `AskUserQuestion`, no "Review & merge / Stop here" prompt. Slice PRs are created and merged automatically. - -### 4a. Create PRs - -For each successfully completed slice in the current tier whose PR does not already exist: - -```bash -gh pr create \ - --head slice/- \ - --base feature/ \ - --title "Slice : " \ - --body "Implements slice of . Part of Tier . - -Signal: " -``` - -Create all PRs for the tier in parallel. - -### 4b. Auto-Merge PRs - -For each PR (in slice-number order): - -```bash -gh pr merge --merge -``` - -**Key constraints:** -- Use `--merge` (NOT `--squash`) — preserves the slice's individual commits plus a merge commit. The merge commit clearly delineates which commits belong to which slice when reviewing the eventual `feature/ → main` PR. -- **Do NOT pass `--delete-branch`** — slice branches stay on origin as archaeological evidence. Reviewers of the feature→main PR can navigate to `slice/-` to see the focused, in-context diff for any slice. - -After each successful merge: -- `git pull origin feature/` in the orchestrator's checkout to bring the merged commits in. - -### 4c. Handle Merge Conflicts - -If `gh pr merge` fails for conflict reasons: -- Attempt automatic resolution for simple conflicts (barrel exports, registry additions, import lists). Same heuristic patterns as the historical code. -- If unresolvable: log which PR failed and which files conflicted, then exit. The dispatcher will re-fire `/implement-mainspec` on the next tick; that invocation's idempotency check will see the failed PR is still open and either retry the merge (if origin now has the prerequisite commits) or skip if the work has moved on. - -### 4d. Worktree Cleanup - -After all PRs for the tier are merged: -- `git worktree remove ` for each slice worktree in this tier. -- Continue to the next tier (subsequent-tier worktrees branch from the updated `feature/`). - -### 4e. Failed Slices Within a Tier - -If any slice in the tier failed in Phase 3 (slice-implementer reported FAILURE): -- Do not create a PR for it. -- Log the failure to stdout with slice number and error details. -- The other tier slices proceed normally through PR creation and auto-merge. -- After the tier completes auto-merge, exit. The dispatcher will re-fire on the next tick; idempotency in Phase 1 will identify the failed slice as REMAINING and retry it. Subsequent tiers must wait until this tier is fully merged, so the exit is the correct behavior. - -## Phase 3/5: Stdout Log (Observability Only) - -There is no human to report to. Write a concise stdout log of what this invocation did so the dispatcher's log is readable. The dispatcher does not parse this output; it only checks `./prds//run-prd-test.sh` exit code externally. - -**Sequential mode log:** +There is no human to report to. Write a concise stdout log of what this invocation did so the dispatcher's log is readable. ``` ## /implement-mainspec invocation summary: -Mode: Sequential -Skipped (already-merged): (or none) +Skipped (already-committed): (or none) Implemented this invocation: Failed this invocation: (or none) Branch: feature/ (pushed) ``` -**Parallel mode log:** - -``` -## /implement-mainspec invocation summary: -Mode: Parallel -Feature branch: feature/ -Skipped (already-merged): (or none) -Tier 0 implemented: -Tier 1 implemented (auto-merged): -Tier 2 implemented (auto-merged): -... -Failed this invocation: (or none) - -If failures: dispatcher will re-fire on next tick; idempotency will skip merged work. -If no failures: dispatcher will verify `./prds//run-prd-test.sh` exits 0 on next tick. -``` - -## Signal Processing - -Signal skills provide runtime feedback during implementation. They validate that code works correctly in real environments. - -### Reading the Signal Section - -Each slice includes a Signal section after the Objective: - -``` -## Signal - -**Signal Skill:** {signal-skill-name | None} - -**Expected Behavior:** -- what should succeed when correctly implemented -``` - -### Signal Workflow - -1. After implementing slice code, check the Signal section -2. If Signal Skill is specified: - - Invoke the signal: `skill: "{signal-name}"` - - Wait for signal output - - Follow the guidance from Signal -3. If signal indicates success: Continue to unit tests -4. If signal indicates failure: - - Review signal output to identify specific issue - - Fix the implementation - - Re-invoke signal - - Repeat until signal validates success -5. If Signal Skill is "None": Skip signal validation, proceed to unit tests - ## TODO Structure -**Sequential mode:** -``` -[ ] X.Y- - Implement -[ ] X.Y- - Signal Validation -[ ] X.Y- - Unit Tests -... -``` - -**Parallel mode:** ``` -[ ] Phase 0 - Mode Detection -[ ] Phase 1 - Parse DAG & resume detection -[ ] Phase 2 - Tier 0 foundation slices (sequential) -[ ] Tier 0: X.Y- - Delegate to slice-implementer -[ ] Tier 0: X.Y- - Git commit & push -[ ] Tier 1: Create worktrees -[ ] Tier 1: Spawn slice-implementer subagents (N slices) -[ ] Tier 1: Wait for completion -[ ] Tier 1: Git commit & push for each worktree -[ ] Tier 1: Create PRs -[ ] Tier 1: Auto-merge PRs (`gh pr merge --merge`) -[ ] Tier 1: Worktree cleanup +[ ] X.Y- +[ ] X.Y- ... -[ ] Phase 5 - Stdout log ``` ## References -Detailed reference material for parallel mode execution: - -- **Subagent prompt template**: Read `references/subagent-prompt-template.md` when spawning subagents in Phase 4 +- **Subagent prompt template**: Read `references/subagent-prompt-template.md` when spawning subagents in Phase 2 - **Error handling**: Read `references/error-handling.md` when any phase encounters errors -- **Release strategy**: Read `references/release-strategy.md` when presenting the summary report or when the user asks about releasing ## Guidelines -### Both Modes - **DO:** - Log the execution plan to stdout for observability (no approval gate; proceed directly). - Use absolute paths for all spec file references. - Delegate slice implementation to `slice-implementer` subagents — orchestrator stays lean. - Use `subagent_type: "slice-implementer"` and `mode: "bypassPermissions"` for all subagent spawns. -- Pass `max_signal_iterations: 3` to each subagent (via the prompt template) so the inner signal-fix loop is bounded. -- Handle all git operations (add, commit, push) in the orchestrator — subagents do NOT run git. +- Handle all git operations (add, commit, push) in the orchestrator — subagents do NOT run git. This includes any Expert-file changes a subagent's Reflect step wrote. - Use `git status` to detect changed files after subagent completion. - Read only the current slice file — never read all slices at once. - Treat the current branch as the feature branch (must match `feature/`); never create it. -- Inspect `feature/` git history at the start of every invocation to determine which slices are already merged; idempotency depends on this. -- On any failure (subagent FAILURE, merge conflict, etc.): log clearly, commit any safe partial state, exit. The dispatcher's next tick is the retry mechanism. +- Inspect `feature/` git history at the start of every invocation to determine which slices are already committed; idempotency depends on this. +- On any failure: log clearly, exit. The dispatcher's next tick is the retry mechanism. **DON'T:** - Use `AskUserQuestion` anywhere. The dispatcher provides no input, and the human is not in the loop. @@ -513,28 +155,5 @@ Detailed reference material for parallel mode execution: - Skip slices or implement out of order (within remaining work). - Proceed with failing tests. - Over-engineer beyond slice scope. -- Skip signal validation when a signal is specified. -- Ignore signal failure indicators. +- Create worktrees, per-slice branches, or PRs for individual slices. - Create a sentinel file for this skill. The dispatcher's success check is `./prds//run-prd-test.sh` exit code, not a sentinel. - -### Sequential Mode Only - -**DON'T:** -- Create PRs for individual slices. -- Create worktrees. - -### Parallel Mode Only - -**DO:** -- Bootstrap every slice worktree via `scripts/bootstrap-worktree.sh` right after `git worktree add`; if the script is absent, warn and continue (do not fail the run). -- Spawn all subagents for a tier in a single message. -- Auto-merge slice PRs with `gh pr merge --merge` (preserving slice commits + a merge commit). Never `--squash`. Never `--delete-branch` — slice branches stay on origin as evidence. -- Clean up worktrees after each tier's PRs are merged. -- Check for existing slice branches/PRs at the start of every invocation; reuse merged ones (skip), reuse open ones (continue auto-merge), recreate branchless ones from `feature/`. - -**DON'T:** -- Use `isolation: "worktree"` — it branches from default branch, missing Tier 0 code. -- Create PRs targeting `main` — always target `feature/`. -- Spawn more than 7 subagents simultaneously (batch if needed). -- Pause for human tier review — there is no human; auto-merge each tier and continue. -- Eagerly merge `main` into `feature/` — only when needed for conflicts during the eventual feature→main PR. \ No newline at end of file diff --git a/skills/sdd/implement-mainspec/references/error-handling.md b/skills/sdd/implement-mainspec/references/error-handling.md index 1b1bfa4..0fe461f 100644 --- a/skills/sdd/implement-mainspec/references/error-handling.md +++ b/skills/sdd/implement-mainspec/references/error-handling.md @@ -2,69 +2,24 @@ Reference for handling errors during mainspec implementation. Read this when any phase encounters errors. -Agent-first model: there is no human in the loop and no orchestrator session waiting on stdout. The retry mechanism is the harness dispatcher: each tick wipes uncommitted state in the worktree and re-invokes `/implement-mainspec`. Idempotency (Phase 1 resume detection) is what makes retries safe — the skill identifies which slices are already merged and works only on remaining ones. +Agent-first model: there is no human in the loop and no orchestrator session waiting on stdout. The retry mechanism is the harness dispatcher: each tick wipes uncommitted state and re-invokes `/implement-mainspec`. Idempotency (Phase 1 resume detection) is what makes retries safe — the skill identifies which slices are already committed and works only on remaining ones. ## 1. Subagent Fails Implementation - Log error details from subagent output to stdout for observability. -- Mark the slice as failed for this invocation; do not create a PR for it. -- Other slices in the same tier are NOT affected — let them finish and auto-merge. -- After the tier finishes auto-merge, exit. The dispatcher's next tick will re-fire `/implement-mainspec`; Phase 1's idempotency check will skip merged slices and retry this one. -- There is no skill-level retry cap. The dispatcher has no attempt counter for this skill (only for `local-checks`). If the same slice keeps failing across many ticks, that is an observability concern, not a skill-design concern. +- Mark the slice as failed for this invocation; do not commit any partial state. +- Exit. The dispatcher's next tick will re-fire `/implement-mainspec`; Phase 1's idempotency check will skip committed slices and retry this one. -## 2. Signal Validation Fails Inside Subagent -- The subagent's `implement-slice` workflow handles this via the bounded inner loop (`max_signal_iterations: 3` — fix code, re-invoke signal, repeat up to 3 times). -- If the cap is hit, the subagent returns FAILURE with `reason: signal_failure` and the last signal output. -- Treat this like §1 — mark slice failed, let tier finish, exit, dispatcher re-fires. - -## 3. PR Creation Fails - -- Usually means the slice branch wasn't pushed or origin is unavailable. -- Log error, continue creating PRs for other slices in the tier. -- The next dispatcher tick will re-enter Phase 4; idempotency will detect the missing PR and retry creation. - -## 4. Tier Auto-Merge — Out-of-Order or Missing Dependency - -- With auto-merge, the orchestrator processes PRs in slice-number order within each tier, and only moves to the next tier after the current tier is fully merged. Out-of-order should not happen. -- If a tier's PR somehow lacks a merged dependency (shouldn't, given Phase 1's DAG-ordered execution): exit. Dispatcher re-fires; Phase 1 will recompute and retry. - -## 5. Merge Conflicts During PR Auto-Merge - -- Attempt automatic resolution for simple, well-known conflict patterns: barrel exports (`index.ts` re-export lists), registry additions (append-only arrays/objects), import lists at file tops. -- If a conflict is outside these patterns or auto-resolution fails: - - Log affected files and the PR number to stdout. - - Commit any safe partial work (typically nothing — the auto-merge step doesn't leave the worktree dirty). - - Exit. The dispatcher's next tick re-fires; the worktree wipe clears any aborted merge state. The next invocation will retry the merge with origin's updated state. - -## 6. Worktree Issues - -- **Path already exists:** the worktree was created by a prior interrupted tick. The dispatcher's tick-start wipe operates on the **outer** worktree; nested per-slice worktrees survive. Check whether the existing slice worktree's branch matches what we want: - - If yes: attach to it via `git worktree add ` (without `-b`). - - If no: `git worktree remove --force ` then recreate. This is safe because per-slice worktrees only ever hold uncommitted slice-implementer output, which is recoverable. -- **Removal fails (uncommitted changes):** log and exit. The next tick will retry. -- **Stale references:** run `git worktree prune` at the end of a successful tier to clean up. - -## 7. Branch Already Exists - -- **Feature branch:** must exist (dispatcher's atomic rename created it). The precondition check verifies HEAD matches `feature/`; exit if not. -- **Slice branch already on origin:** auto-detect via `gh pr view --json state -q .state`: - - `MERGED` → slice is done; skip in this invocation. - - `OPEN` → PR was created but not yet merged; pick up at the Phase 4 auto-merge step. - - No PR found → branch has commits but no PR was created. Continue: Phase 4 creates the PR, then merges it. - - Branch with no commits past `feature/` HEAD → recreate the worktree on top. -- Never delete a slice branch automatically. Branches are evidence; preservation is intentional. - -## 8. Push Fails +## 2. Push Fails - Preconditions require a remote, so this means transient network / auth failure or remote rejection. - Log and exit. The dispatcher's next tick will retry. There is no fallback to "local-only mode" — the harness model assumes remote is available. -## 9. Resuming After Interruption +## 3. Resuming After Interruption - Every dispatcher tick wipes uncommitted state in the worktree (`git reset --hard HEAD && git clean -fd`) and re-invokes `/implement-mainspec`. - The skill re-derives all state from disk on every invocation: - - What's merged on `feature/` (Phase 1 idempotency check). - - Which slice branches exist on origin and the state of their PRs (Phase 4 prep). - - Which worktrees exist locally (Worktree Management section in SKILL.md). -- No checkpoint files or in-memory state to persist; the artifacts on disk ARE the state. + - What's committed on `feature/` (Phase 1 idempotency check via `git log --oneline --grep "Implement slice"`). +- No checkpoint files or in-memory state to persist; the git history IS the state. +- **Feature branch:** must exist (dispatcher's atomic rename created it). The precondition check verifies HEAD matches `feature/`; exit if not. diff --git a/skills/sdd/implement-mainspec/references/release-strategy.md b/skills/sdd/implement-mainspec/references/release-strategy.md deleted file mode 100644 index e568a32..0000000 --- a/skills/sdd/implement-mainspec/references/release-strategy.md +++ /dev/null @@ -1,49 +0,0 @@ -# Release Strategy (Parallel Mode) - -The feature branch IS the release candidate. PR `feature/` to `main` directly. No separate release branches. - -## When to Release - -The developer can release at any point during implementation: -- After Tier 0 (foundation only) -- After any tier's PRs are merged -- After all tiers are complete - -The natural release unit is "everything merged to feat so far." - -For partial release: leave unwanted slice PRs unmerged on feat, then PR feat to main with only the desired slices. - -## How to Release - -```bash -gh pr create --base main --head feature/ \ - --title "Release: " \ - --body "Includes slices: " -``` - -## Lazy Merge Policy - -After releasing (merging feat to main), do NOT immediately merge main back into feat. Only merge main into feat when: - -1. Next release PR has merge conflicts with main -2. The feat branch needs changes that landed on main after the release - -Git/GitHub handles the diff correctly — it knows what was already merged. - -### If Merging main into feat for Conflict Resolution - -```bash -git checkout feature/ -git merge main -# Resolve any conflicts -# Run tests to verify nothing broke -git push origin feature/ -# Then create the release PR -``` - -## Partial Release Constraints - -The dependency DAG determines valid release subsets: -- Can't ship a slice without its dependencies (e.g., can't ship 3.6 without 3.2-3.5) -- Only merge slice PRs whose dependencies are also merged -- The summary report (Phase 6) lists valid release subsets diff --git a/skills/sdd/implement-mainspec/references/subagent-prompt-template.md b/skills/sdd/implement-mainspec/references/subagent-prompt-template.md index 255f808..de804cc 100644 --- a/skills/sdd/implement-mainspec/references/subagent-prompt-template.md +++ b/skills/sdd/implement-mainspec/references/subagent-prompt-template.md @@ -1,6 +1,6 @@ # Subagent Prompt Template -Use this template when spawning subagents for any tier (including Tier 0). Fill in the placeholder values for each slice. +Use this template when spawning the `slice-implementer` subagent. Fill in the placeholder values for each slice. ## Template @@ -15,16 +15,19 @@ Read the slice file at: (This is an absolute path — it may be outside your working directory) -Follow the implement-slice workflow (preloaded in your context) to implement the slice. +Follow the implement-slice workflow (preloaded in your context) to implement the slice: +Implement → Unit Tests → Reflect Report your result: - - SUCCESS: all code implemented, tests pass. List key files created/modified. + - SUCCESS: all code implemented, tests pass, Reflect outcome (no-op | add | edit | delete). + List key files created/modified (including any Expert reference files touched during Reflect). - FAILURE: describe what went wrong and where you stopped. Do NOT use AskUserQuestion — no human is in the loop. Do NOT run any git commands (add, commit, push) — the orchestrator handles git. -Do NOT create a PR — the orchestrator handles PR creation. -Do NOT modify files outside your assigned slice scope. +Do NOT create a PR — the orchestrator handles all git operations. +Do NOT modify files outside your assigned slice scope (exception: `.claude/skills/expert/references/` + edits during the Reflect step are explicitly in-scope). Do NOT use git worktree commands — you are already in the correct directory. ``` @@ -32,16 +35,14 @@ Do NOT use git worktree commands — you are already in the correct directory. | Placeholder | Source | Example | |------------|--------|---------| -| `` | compute_tiers.py output → slice number | `3.3` | -| `` | compute_tiers.py output → slice name | `BarChart Component` | -| `` | compute_tiers.py output → mainspec_name | `svg-and-charts` | -| `` | For Tier 0: repo root. For Tier 1+: `realpath .claude/worktrees//` | `/home/user/repo/.claude/worktrees/svg-and-charts/slice-3.3-barchart` | -| `` | compute_tiers.py output → slice file | `/home/user/specs/svg-and-charts/slices/3.3-barchart-component.md` | +| `` | Slice Dependency Map → slice number | `3.3` | +| `` | Slice Dependency Map → slice name | `BarChart Component` | +| `` | mainspec.md → feature slug | `svg-and-charts` | +| `` | Repo root | `/home/user/repo` | +| `` | `specs//slices/-.md` (resolved to absolute path) | `/home/user/repo/specs/svg-and-charts/slices/3.3-barchart-component.md` | ## Usage -### Tier 0 (Sequential — foreground) - Spawn one subagent at a time. Wait for completion before spawning the next. ```python @@ -54,48 +55,5 @@ Agent( ) # Wait for completion # Orchestrator runs: git add, git commit, git push -# Then spawn next Tier 0 slice -``` - -### Tier 1+ (Parallel — background) - -Spawn all subagents for a tier in a **single message** for maximum parallelism: - -```python -Agent( - subagent_type="slice-implementer", - run_in_background=True, - mode="bypassPermissions", - name="slice-3.2", - description="Implement slice 3.2", - prompt="" -) -Agent( - subagent_type="slice-implementer", - run_in_background=True, - mode="bypassPermissions", - name="slice-3.3", - description="Implement slice 3.3", - prompt="" -) -# ... one per slice in the tier -# Wait for all to complete -# Orchestrator handles git for each worktree -``` - -### Sequential Mode - -Same as Tier 0 — spawn one at a time, foreground, orchestrator handles git after each. - -```python -Agent( - subagent_type="slice-implementer", - mode="bypassPermissions", - name="slice-1.1", - description="Implement slice 1.1", - prompt="" -) -# Wait for completion -# Orchestrator runs: git add, git commit # Then spawn next slice ``` diff --git a/skills/sdd/implement-mainspec/scripts/compute_tiers.py b/skills/sdd/implement-mainspec/scripts/compute_tiers.py deleted file mode 100644 index 06e5d99..0000000 --- a/skills/sdd/implement-mainspec/scripts/compute_tiers.py +++ /dev/null @@ -1,253 +0,0 @@ -#!/usr/bin/env python3 -"""Compute parallelizable tiers from a mainspec's Slice Dependency Map. - -Parses the markdown dependency table, builds a DAG, runs topological sort -to group slices into tiers, and outputs JSON with tier assignments and -naming conventions. - -Usage: - python compute_tiers.py -""" - -import json -import re -import sys -from dataclasses import dataclass, field -from pathlib import Path - - -class CircularDependencyError(Exception): - """Raised when the dependency graph contains a cycle.""" - - pass - - -@dataclass -class SliceInfo: - number: str - name: str - depends_on: list[str] = field(default_factory=list) - blocks: list[str] = field(default_factory=list) - file: str = "" - - -def _parse_refs(col: str) -> list[str]: - """Parse a comma-separated list of slice references. - - Returns empty list for '—', '–', '-', 'Nothing', or empty string. - """ - col = col.strip() - if col in ("—", "–", "-", "Nothing", ""): - return [] - return [ref.strip() for ref in col.split(",") if ref.strip()] - - -def parse_dependency_table(content: str) -> list[SliceInfo]: - """Parse the Slice Dependency Map table from mainspec content. - - Expects a section headed '## Slice Dependency Map' with a markdown table - having at minimum Slice and Depends On columns. Blocks column is optional. - """ - lines = content.split("\n") - - # Find the "## Slice Dependency Map" section - in_section = False - table_lines = [] - for line in lines: - if re.match(r"^##\s+Slice Dependency Map", line): - in_section = True - continue - if in_section: - if line.startswith("## "): - break - if line.startswith("|"): - table_lines.append(line) - - if len(table_lines) < 3: - raise ValueError( - "No valid dependency table found in 'Slice Dependency Map' section" - ) - - # Determine column indices from header - header_cols = [c.strip().lower() for c in table_lines[0].split("|")] - # Filter empty strings from leading/trailing pipes - col_map = {} - for i, col in enumerate(header_cols): - if "slice" in col and "slice" not in col_map: - col_map["slice"] = i - elif "depends" in col: - col_map["depends_on"] = i - elif "blocks" in col: - col_map["blocks"] = i - - if "slice" not in col_map or "depends_on" not in col_map: - raise ValueError( - f"Table must have 'Slice' and 'Depends On' columns. Found: {header_cols}" - ) - - has_blocks = "blocks" in col_map - - # Parse data rows (skip header + separator) - slices = [] - for row in table_lines[2:]: - cols = [c.strip() for c in row.split("|")] - if len(cols) <= col_map["slice"]: - continue - - slice_col = cols[col_map["slice"]].strip() - depends_col = cols[col_map["depends_on"]].strip() - blocks_col = cols[col_map["blocks"]].strip() if has_blocks and len(cols) > col_map["blocks"] else "" - - # Parse slice column: "X.Y — Name" or "X.Y - Name" - match = re.match(r"^([\d.]+)\s*[—–\-]\s*(.+)$", slice_col) - if not match: - continue - - number = match.group(1) - name = match.group(2).strip() - - slices.append( - SliceInfo( - number=number, - name=name, - depends_on=_parse_refs(depends_col), - blocks=_parse_refs(blocks_col), - file="", - ) - ) - - return slices - - -def compute_tiers(slices: list[SliceInfo]) -> list[list[SliceInfo]]: - """Compute parallelizable tiers via topological sort. - - Tier 0 = slices with no dependencies. - Tier N = slices whose ALL dependencies are in tiers 0..N-1. - - Raises CircularDependencyError if the graph has cycles. - """ - if not slices: - return [] - - remaining = {s.number: s for s in slices} - assigned: set[str] = set() - tiers: list[list[SliceInfo]] = [] - - while remaining: - current_tier = [ - s - for s in remaining.values() - if all(dep in assigned for dep in s.depends_on) - ] - - if not current_tier: - raise CircularDependencyError( - f"Circular dependency detected. Remaining slices: {list(remaining.keys())}" - ) - - # Sort by slice number for deterministic output - current_tier.sort(key=lambda s: [int(x) for x in s.number.split(".")]) - tiers.append(current_tier) - - for s in current_tier: - assigned.add(s.number) - del remaining[s.number] - - return tiers - - -def to_kebab(name: str) -> str: - """Convert a name to kebab-case. - - Handles CamelCase, spaces, and special characters. - """ - # Insert hyphens before uppercase letters (CamelCase → camel-case) - s = re.sub(r"([a-z0-9])([A-Z])", r"\1-\2", name) - # Replace non-alphanumeric with hyphens - s = re.sub(r"[^a-z0-9]+", "-", s.lower()) - # Collapse multiple hyphens, strip leading/trailing - s = re.sub(r"-+", "-", s).strip("-") - return s - - -def feature_branch_name(mainspec_name: str) -> str: - """Compute feature branch name from mainspec directory name.""" - return f"feature/{mainspec_name}" - - -def slice_branch_name(number: str, name: str) -> str: - """Compute slice branch name.""" - return f"slice/{number}-{to_kebab(name)}" - - -def worktree_path(mainspec_name: str, number: str, name: str) -> str: - """Compute worktree path for a slice, namespaced under the mainspec.""" - return f".claude/worktrees/{mainspec_name}/slice-{number}-{to_kebab(name)}" - - -def batch_slices(slices: list, max_agents: int = 7) -> list[list]: - """Split a tier's slices into batches of max_agents.""" - if not slices: - return [] - return [slices[i : i + max_agents] for i in range(0, len(slices), max_agents)] - - -def resolve_slice_files(slices: list[SliceInfo], mainspec_path: str) -> None: - """Resolve slice file paths to absolute paths from the slices/ directory. - - Mutates each SliceInfo.file in place. Paths are absolute so subagents - in worktrees can read them regardless of working directory. - """ - spec_dir = Path(mainspec_path).resolve().parent - slices_dir = spec_dir / "slices" - - if not slices_dir.exists(): - return - - files = list(slices_dir.glob("*.md")) - for s in slices: - for f in files: - if f.name.startswith(f"{s.number}-"): - s.file = str(f.resolve()) - break - - -def analyze_mainspec(mainspec_path: str) -> dict: - """Full analysis: parse, compute tiers, resolve files, return JSON-ready dict.""" - path = Path(mainspec_path) - content = path.read_text() - - mainspec_name = path.parent.name - - slices = parse_dependency_table(content) - resolve_slice_files(slices, mainspec_path) - tiers = compute_tiers(slices) - - max_parallel = max(len(t) for t in tiers) if tiers else 0 - - return { - "mainspec_name": mainspec_name, - "feature_branch": feature_branch_name(mainspec_name), - "tiers": [ - { - "tier": i, - "slices": [ - {"number": s.number, "name": s.name, "file": s.file} - for s in tier - ], - } - for i, tier in enumerate(tiers) - ], - "total_slices": sum(len(t) for t in tiers), - "max_parallel": max_parallel, - } - - -if __name__ == "__main__": - if len(sys.argv) != 2: - print("Usage: compute_tiers.py ", file=sys.stderr) - sys.exit(1) - - result = analyze_mainspec(sys.argv[1]) - print(json.dumps(result, indent=2)) diff --git a/skills/sdd/implement-mainspec/scripts/tests/test_tier_computation.py b/skills/sdd/implement-mainspec/scripts/tests/test_tier_computation.py deleted file mode 100644 index dc5893c..0000000 --- a/skills/sdd/implement-mainspec/scripts/tests/test_tier_computation.py +++ /dev/null @@ -1,332 +0,0 @@ -"""Tests for compute_tiers.py — tier computation from mainspec dependency tables. - -Validates the algorithm against real mainspecs and synthetic DAG patterns. -""" - -import sys -from pathlib import Path - -import pytest - -# Add scripts directory to path so we can import compute_tiers -SCRIPTS_DIR = Path(__file__).resolve().parent.parent -sys.path.insert(0, str(SCRIPTS_DIR)) - -from compute_tiers import ( - CircularDependencyError, - SliceInfo, - analyze_mainspec, - batch_slices, - compute_tiers, - feature_branch_name, - parse_dependency_table, - slice_branch_name, - to_kebab, - worktree_path, -) - -PROJECT_ROOT = Path(__file__).resolve().parents[5] -SPECS_DIR = PROJECT_ROOT / "specs" - - -# --------------------------------------------------------------------------- -# Helper: build SliceInfo list from a compact dict -# --------------------------------------------------------------------------- - - -def _make_slices(deps: dict[str, list[str]]) -> list[SliceInfo]: - """Create SliceInfo list from {number: [dep_numbers]} dict.""" - return [ - SliceInfo(number=num, name=f"Slice {num}", depends_on=dep_list) - for num, dep_list in deps.items() - ] - - -def _tier_numbers(tiers: list[list[SliceInfo]]) -> list[list[str]]: - """Extract just the slice numbers from tier results.""" - return [sorted([s.number for s in tier]) for tier in tiers] - - -# =========================================================================== -# Real mainspec tests -# =========================================================================== - - -class TestSvgChartsTiers: - """specs/svg-and-charts/mainspec.md → 3 tiers.""" - - @pytest.fixture() - def result(self): - path = SPECS_DIR / "svg-and-charts" / "mainspec.md" - return analyze_mainspec(str(path)) - - def test_tier_count(self, result): - assert len(result["tiers"]) == 3 - - def test_tier_0(self, result): - numbers = [s["number"] for s in result["tiers"][0]["slices"]] - assert numbers == ["3.1"] - - def test_tier_1(self, result): - numbers = sorted([s["number"] for s in result["tiers"][1]["slices"]]) - assert numbers == ["3.2", "3.3", "3.4", "3.5"] - - def test_tier_2(self, result): - numbers = [s["number"] for s in result["tiers"][2]["slices"]] - assert numbers == ["3.6"] - - def test_total_slices(self, result): - assert result["total_slices"] == 6 - - def test_max_parallel(self, result): - assert result["max_parallel"] == 4 - - def test_feature_branch(self, result): - assert result["feature_branch"] == "feature/svg-and-charts" - - def test_slice_files_resolved(self, result): - for tier in result["tiers"]: - for s in tier["slices"]: - assert s["file"], f"Slice {s['number']} has no resolved file" - assert Path(s["file"]).is_absolute(), f"Slice {s['number']} file is not absolute: {s['file']}" - assert Path(s["file"]).exists(), f"Slice {s['number']} file does not exist: {s['file']}" - - -class TestSceneTransitionsTiers: - """specs/scene-transitions/mainspec.md → 4 tiers.""" - - @pytest.fixture() - def result(self): - path = SPECS_DIR / "scene-transitions" / "mainspec.md" - return analyze_mainspec(str(path)) - - def test_tier_count(self, result): - assert len(result["tiers"]) == 4 - - def test_tier_0(self, result): - numbers = [s["number"] for s in result["tiers"][0]["slices"]] - assert numbers == ["2.1"] - - def test_tier_1(self, result): - numbers = [s["number"] for s in result["tiers"][1]["slices"]] - assert numbers == ["2.2"] - - def test_tier_2(self, result): - numbers = sorted([s["number"] for s in result["tiers"][2]["slices"]]) - assert numbers == ["2.3", "2.5"] - - def test_tier_3(self, result): - numbers = [s["number"] for s in result["tiers"][3]["slices"]] - assert numbers == ["2.4"] - - -class TestImplementParallelTiers: - """specs/implement-mainspec-parallel/mainspec.md → 3 tiers (linear chain).""" - - @pytest.fixture() - def result(self): - path = SPECS_DIR / "implement-mainspec-parallel" / "mainspec.md" - return analyze_mainspec(str(path)) - - def test_tier_count(self, result): - assert len(result["tiers"]) == 3 - - def test_tier_0(self, result): - numbers = [s["number"] for s in result["tiers"][0]["slices"]] - assert numbers == ["1.1"] - - def test_tier_1(self, result): - numbers = [s["number"] for s in result["tiers"][1]["slices"]] - assert numbers == ["1.2"] - - def test_tier_2(self, result): - numbers = [s["number"] for s in result["tiers"][2]["slices"]] - assert numbers == ["1.3"] - - -# =========================================================================== -# Synthetic DAG pattern tests -# =========================================================================== - - -class TestLinearChain: - """A → B → C → D → 4 tiers, 1 slice each.""" - - def test_tiers(self): - slices = _make_slices({ - "1.1": [], - "1.2": ["1.1"], - "1.3": ["1.2"], - "1.4": ["1.3"], - }) - tiers = compute_tiers(slices) - assert len(tiers) == 4 - for tier in tiers: - assert len(tier) == 1 - - -class TestFullFanout: - """A → {B, C, D, E} → 2 tiers: [A], [B, C, D, E].""" - - def test_tiers(self): - slices = _make_slices({ - "1.1": [], - "1.2": ["1.1"], - "1.3": ["1.1"], - "1.4": ["1.1"], - "1.5": ["1.1"], - }) - tiers = compute_tiers(slices) - assert _tier_numbers(tiers) == [["1.1"], ["1.2", "1.3", "1.4", "1.5"]] - - -class TestDiamond: - """A → {B, C}, {B, C} → D → 3 tiers: [A], [B, C], [D].""" - - def test_tiers(self): - slices = _make_slices({ - "1.1": [], - "1.2": ["1.1"], - "1.3": ["1.1"], - "1.4": ["1.2", "1.3"], - }) - tiers = compute_tiers(slices) - assert _tier_numbers(tiers) == [["1.1"], ["1.2", "1.3"], ["1.4"]] - - -class TestCircularDependency: - """A → B → C → A → raises CircularDependencyError.""" - - def test_raises(self): - slices = _make_slices({ - "1.1": ["1.3"], - "1.2": ["1.1"], - "1.3": ["1.2"], - }) - with pytest.raises(CircularDependencyError): - compute_tiers(slices) - - -class TestNoDependencies: - """{A, B, C} independent → 1 tier: [A, B, C].""" - - def test_tiers(self): - slices = _make_slices({ - "1.1": [], - "1.2": [], - "1.3": [], - }) - tiers = compute_tiers(slices) - assert len(tiers) == 1 - assert _tier_numbers(tiers) == [["1.1", "1.2", "1.3"]] - - -# =========================================================================== -# Naming convention tests -# =========================================================================== - - -class TestFeatureBranchNaming: - def test_basic(self): - assert feature_branch_name("svg-and-charts") == "feature/svg-and-charts" - - def test_with_hyphens(self): - assert feature_branch_name("implement-mainspec-parallel") == "feature/implement-mainspec-parallel" - - -class TestSliceBranchNaming: - def test_basic(self): - assert slice_branch_name("3.3", "barchart") == "slice/3.3-barchart" - - def test_multi_word(self): - assert slice_branch_name("3.1", "svg path utilities") == "slice/3.1-svg-path-utilities" - - -class TestWorktreePath: - def test_basic(self): - assert worktree_path("svg-and-charts", "3.3", "barchart") == ".claude/worktrees/svg-and-charts/slice-3.3-barchart" - - def test_multi_word(self): - assert worktree_path("scene-transitions", "2.1", "scene plan types") == ".claude/worktrees/scene-transitions/slice-2.1-scene-plan-types" - - -class TestToKebab: - def test_lowercase(self): - assert to_kebab("barchart") == "barchart" - - def test_camelcase(self): - assert to_kebab("BarChart") == "bar-chart" - - def test_spaces(self): - assert to_kebab("SVG Path Utilities") == "svg-path-utilities" - - def test_special_chars(self): - assert to_kebab("Registry, Docs & Planner") == "registry-docs-planner" - - -# =========================================================================== -# Batching tests -# =========================================================================== - - -class TestBatching: - def test_large_tier(self): - """12 slices with max_agents=7 → 2 batches: [7, 5].""" - items = list(range(12)) - batches = batch_slices(items, max_agents=7) - assert len(batches) == 2 - assert len(batches[0]) == 7 - assert len(batches[1]) == 5 - - def test_exact_fit(self): - """7 slices with max_agents=7 → 1 batch.""" - items = list(range(7)) - batches = batch_slices(items, max_agents=7) - assert len(batches) == 1 - assert len(batches[0]) == 7 - - def test_small_tier(self): - """3 slices with max_agents=7 → 1 batch.""" - items = list(range(3)) - batches = batch_slices(items, max_agents=7) - assert len(batches) == 1 - assert len(batches[0]) == 3 - - def test_empty(self): - assert batch_slices([], max_agents=7) == [] - - -# =========================================================================== -# Table parsing tests -# =========================================================================== - - -class TestParseDependencyTable: - def test_basic_table(self): - content = """## Slice Dependency Map - -| Slice | Depends On | Blocks | -|-------|-----------|--------| -| 1.1 — Foundation | — | 1.2 | -| 1.2 — Feature | 1.1 | — | -""" - slices = parse_dependency_table(content) - assert len(slices) == 2 - assert slices[0].number == "1.1" - assert slices[0].name == "Foundation" - assert slices[0].depends_on == [] - assert slices[1].depends_on == ["1.1"] - - def test_missing_section_raises(self): - with pytest.raises(ValueError): - parse_dependency_table("# No dependency table here") - - def test_multiple_deps(self): - content = """## Slice Dependency Map - -| Slice | Depends On | Blocks | -|-------|-----------|--------| -| 1.3 — Final | 1.1, 1.2 | — | -""" - slices = parse_dependency_table(content) - assert slices[0].depends_on == ["1.1", "1.2"] diff --git a/subagents/slice-implementer.md b/subagents/slice-implementer.md index 74d62d0..0378742 100644 --- a/subagents/slice-implementer.md +++ b/subagents/slice-implementer.md @@ -1,6 +1,6 @@ --- name: slice-implementer -description: Implements a single slice in a worktree. Used by implement-mainspec for parallel tier execution. +description: Implements a single slice. Used by implement-mainspec to implement one slice on the feature branch. skills: - implement-slice permissionMode: bypassPermissions From 617f0e6d98e28122d1f36d180118c99b714a7e01 Mon Sep 17 00:00:00 2001 From: Rico Date: Sun, 5 Jul 2026 12:57:03 -0500 Subject: [PATCH 05/14] Remove expert-sdd-creator, install-agents.sh, stale implement-mainspec scripts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit expert-sdd-creator still references the retired Signal concept and creates outside experts — it will be redesigned separately. install-agents.sh is absorbed by the upcoming context-specs CLI. implement-mainspec/scripts held only orphaned __pycache__ bytecode. Co-Authored-By: Claude Fable 5 --- install-agents.sh | 49 --- skills/sdd/expert-sdd-creator/SKILL.md | 158 -------- .../references/catalog-formats.md | 189 --------- .../references/expert-structure.md | 231 ----------- .../references/signal-patterns.md | 367 ------------------ .../scripts/register_expert.sh | 262 ------------- .../scripts/validate_expert.sh | 202 ---------- 7 files changed, 1458 deletions(-) delete mode 100755 install-agents.sh delete mode 100644 skills/sdd/expert-sdd-creator/SKILL.md delete mode 100644 skills/sdd/expert-sdd-creator/references/catalog-formats.md delete mode 100644 skills/sdd/expert-sdd-creator/references/expert-structure.md delete mode 100644 skills/sdd/expert-sdd-creator/references/signal-patterns.md delete mode 100755 skills/sdd/expert-sdd-creator/scripts/register_expert.sh delete mode 100755 skills/sdd/expert-sdd-creator/scripts/validate_expert.sh diff --git a/install-agents.sh b/install-agents.sh deleted file mode 100755 index 2f31868..0000000 --- a/install-agents.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -REPO_URL="https://github.com/capitalone/context-specs.git" -TEMP_DIR="" - -cleanup() { - if [ -n "$TEMP_DIR" ] && [ -d "$TEMP_DIR" ]; then - rm -rf "$TEMP_DIR" - fi -} -trap cleanup EXIT - -echo "Installing context-specs agents..." - -# Clone into a temp directory -TEMP_DIR="$(mktemp -d)" -git clone --depth 1 --quiet "$REPO_URL" "$TEMP_DIR" - -# Verify source agents exist -SOURCE_DIR="$TEMP_DIR/subagents" -if [ ! -d "$SOURCE_DIR" ]; then - echo "Error: No subagents/ directory found in the repository." >&2 - exit 1 -fi - -# Create target directory -mkdir -p .claude/agents - -# Copy agent definitions -INSTALLED=() -for file in "$SOURCE_DIR"/*.md; do - [ -f "$file" ] || continue - cp "$file" ".claude/agents/$(basename "$file")" - INSTALLED+=("$(basename "$file")") -done - -if [ ${#INSTALLED[@]} -eq 0 ]; then - echo "No agent definitions found to install." - exit 0 -fi - -echo "" -echo "Installed ${#INSTALLED[@]} agent(s) into .claude/agents/:" -for name in "${INSTALLED[@]}"; do - echo " - $name" -done -echo "" -echo "Done." diff --git a/skills/sdd/expert-sdd-creator/SKILL.md b/skills/sdd/expert-sdd-creator/SKILL.md deleted file mode 100644 index 086e2e3..0000000 --- a/skills/sdd/expert-sdd-creator/SKILL.md +++ /dev/null @@ -1,158 +0,0 @@ ---- -name: expert-sdd-creator -description: Meta skill for creating new SDD experts from domain documentation. Provide a markdown file path with domain knowledge + optional steering context. Automatically synthesizes references, generates signal scripts, validates, and registers in experts.md/signals.md catalogs. Single-prompt creation with follow-up tweaks. Triggers - create expert, new expert, make expert, expert for, domain expert, add expert (project) ---- - -# Expert SDD Creator - -Create SDD experts from domain documentation in a single prompt. - -## Required Input - -1. **Domain docs** (required): Path to markdown file with domain knowledge -2. **Steering** (optional but recommended): What to focus on, specific use cases - -Example prompt: -``` -Create an expert for my custom testing framework. -Docs: /path/to/custom-docs.md -Focus on: component testing, live dependency testing, Cucumber BDD patterns -``` - ---- - -## Creation Process - -### 1. Analyze Input - -Read the markdown file and steering context to determine: -- Expert name (kebab-case, prefixed with `expert-`) -- Triggers (keywords that invoke this expert) -- Key topics for reference files -- Signal validation approach - -### 2. Generate Expert Structure - -Create directory at `.claude/skills/expert-{name}/` (sibling to this skill's directory): - -``` -expert-{name}/ -├── SKILL.md # Frontmatter + Expert Mode + Signal Mode -├── references/ -│ ├── {topic-1}.md # Synthesized from input docs -│ ├── {topic-N}.md -│ └── signal-workflow.md # How signal validates behavior -└── scripts/ - ├── run_signal.sh # Main signal execution - └── {helper}.sh # Additional helpers as needed -``` - -### 3. Synthesize References - -From the input markdown: -- Extract key topics and organize into separate reference files -- Keep each file focused on one topic -- Include practical examples and patterns -- Create `signal-workflow.md` describing validation approach - -### 4. Generate Signal Scripts - -Analyze domain to determine appropriate signal approach: - -| Domain Type | Signal Approach | -|-------------|-----------------| -| Testing (Cucumber, JUnit) | Run tests, parse results | -| API/Service (REST, GraphQL) | Call endpoints, check responses | -| Build/Deploy (Maven, Gradle) | Run build, check artifacts | -| Config/Data (YAML, JSON) | Validate syntax, check schema | -| CLI tools (flyway, kubectl) | Run commands, parse output | - -Generate `run_signal.sh` with domain-specific checks and TODOs for customization. - -### 5. Write SKILL.md - -Structure the expert's SKILL.md: - -```yaml ---- -name: expert-{name} -description: {domain} expertise with signal capability. {what it provides}. Triggers: {trigger-list} (project) ---- -``` - -Body includes: -- **Expert Mode**: Quick reference table, navigation to references -- **Signal Mode**: Quick commands, reference to signal-workflow.md - -### 6. Validate & Register - -Run validation: -```bash -scripts/validate_expert.sh /path/to/expert-{name} -``` - -If valid, register: -```bash -scripts/register_expert.sh /path/to/expert-{name} -``` - -### 7. Report Results - -Output to user: -- Created directory structure -- List of synthesized reference files -- Signal approach explanation -- Registration locations (line numbers in experts.md/signals.md) -- Path to expert for tweaking -- Any clarifying questions about signal scripts - ---- - -## Expert Structure Requirements - -Every expert must have: - -1. **SKILL.md** with valid YAML frontmatter: - - `name`: expert-{name} format - - `description`: includes triggers and "(project)" suffix - -2. **references/** directory with: - - At least one domain knowledge file - - `signal-workflow.md` describing validation approach - -3. **scripts/** directory with: - - `run_signal.sh` (executable) - - Helper scripts as needed - -→ See `references/expert-structure.md` for detailed patterns - ---- - -## Signal Mode - -Validate and register created experts. - -### Quick Commands - -| Action | Command | -|--------|---------| -| Validate | `scripts/validate_expert.sh ` | -| Register | `scripts/register_expert.sh ` | - -### Validation Checks - -- Directory structure complete (SKILL.md, references/, scripts/) -- YAML frontmatter valid (name, description) -- references/ contains files -- scripts/run_signal.sh exists and is executable -- signal-workflow.md present - -### Registration - -- Parses expert metadata from SKILL.md -- Generates entries for experts.md and signals.md -- Inserts at end of Expert Entries / Signal Entries section -- Reports line numbers of insertions - -→ See `references/catalog-formats.md` for entry formats -→ See `references/signal-patterns.md` for signal script patterns diff --git a/skills/sdd/expert-sdd-creator/references/catalog-formats.md b/skills/sdd/expert-sdd-creator/references/catalog-formats.md deleted file mode 100644 index 0d6085e..0000000 --- a/skills/sdd/expert-sdd-creator/references/catalog-formats.md +++ /dev/null @@ -1,189 +0,0 @@ -# Catalog Entry Formats - -Formats for registering experts in `experts.md` and `signals.md` catalogs. - -Location of catalogs (sibling to this skill's install directory): -- `.claude/skills/spec-planning/references/experts.md` -- `.claude/skills/spec-planning/references/signals.md` - ---- - -## experts.md Entry Format - -Add under `## Expert Entries` section: - -```markdown -### N. {expert-name} - -**Description:** {2-3 sentence description of what the expert provides} - -**Triggers:** -- {trigger-1} -- {trigger-2} -- {trigger-N} - -**What It Provides:** -- {capability-1} -- {capability-2} -- {capability-N} - -**Signal Capability:** -- {signal-validation-1} -- {signal-validation-N} - -**Skill Name:** `{expert-name}` - ---- -``` - -### Field Details - -| Field | Description | -|-------|-------------| -| N | Sequential number (next after last entry) | -| expert-name | Matches `name` from SKILL.md frontmatter | -| Description | Domain expertise summary + signal capability mention | -| Triggers | Keywords that invoke this expert (from frontmatter) | -| What It Provides | Expert mode capabilities (from references) | -| Signal Capability | What signal mode validates | -| Skill Name | Exact skill name for invocation | - -### Example Entry - -```markdown -### 4. expert-migrations - -**Description:** Database migration expertise for Flyway and Liquibase. Provides schema versioning patterns, rollback strategies, and CI/CD integration guidance. Includes signal capability for migration status validation. - -**Triggers:** -- Flyway, Liquibase, database migrations -- Schema versioning, DDL changes -- Rollback, migration status -- Signal, verify migrations - -**What It Provides:** -- Migration file naming and versioning conventions -- Rollback strategy patterns -- CI/CD pipeline integration -- Troubleshooting common migration failures - -**Signal Capability:** -- Migration status check (pending, applied, failed) -- Schema validation -- Rollback verification - -**Skill Name:** `expert-migrations` - ---- -``` - ---- - -## signals.md Entry Format - -Add under `## Signal Entries` section: - -```markdown -### N. {expert-name} (with signal capability) - -**Description:** {1 sentence describing what the signal validates} - -**Triggers:** -- {signal-trigger-1} -- {signal-trigger-2} -- {signal-trigger-N} - -**What It Validates:** -- {validation-1} -- {validation-2} -- {validation-N} - -**How to Invoke:** `skill: "{expert-name}"` - -**Typical Expected Behaviors:** -- {expected-behavior-1} -- {expected-behavior-2} -- {expected-behavior-N} - -**Typical Failure Indicators:** -- {failure-indicator-1} -- {failure-indicator-2} -- {failure-indicator-N} - -**Skill Name:** `{expert-name}` - ---- -``` - -### Field Details - -| Field | Description | -|-------|-------------| -| N | Sequential number (next after last entry) | -| expert-name | Matches `name` from SKILL.md frontmatter | -| Description | What signal mode validates (1 sentence) | -| Triggers | Keywords that invoke signal mode | -| What It Validates | Specific validations performed | -| How to Invoke | Skill invocation syntax | -| Expected Behaviors | What success looks like | -| Failure Indicators | What failure looks like | - -### Example Entry - -```markdown -### 4. expert-migrations (with signal capability) - -**Description:** Runtime validation for database migration status and schema consistency. - -**Triggers:** -- Check migration status, verify migrations -- Run flyway info, liquibase status -- Signal, migration validation - -**What It Validates:** -- Migration execution status (pending, applied, failed) -- Schema version consistency -- Rollback capability verification - -**How to Invoke:** `skill: "expert-migrations"` - -**Typical Expected Behaviors:** -- All migrations show "applied" status -- Schema version matches expected version -- No pending migrations in production - -**Typical Failure Indicators:** -- Migrations show "pending" or "failed" status -- Schema version mismatch -- Connection errors to database -- Checksum validation failures - -**Skill Name:** `expert-migrations` - ---- -``` - ---- - -## Insertion Rules - -1. **Position**: Add after the last `### N.` entry in each file -2. **Numbering**: Increment N from the last entry -3. **Separator**: Include `---` after each entry -4. **Both files**: Always update both experts.md AND signals.md - ---- - -## Extraction from SKILL.md - -The `register_expert.sh` script extracts: - -| Catalog Field | Source | -|---------------|--------| -| expert-name | `name` from frontmatter | -| Description | `description` from frontmatter (truncated/adapted) | -| Triggers | Parsed from `description` after "Triggers:" | -| What It Provides | Derived from reference file names | -| Signal Capability | Derived from signal-workflow.md | -| Expected Behaviors | From signal-workflow.md "Success" section | -| Failure Indicators | From signal-workflow.md "Failure" section | diff --git a/skills/sdd/expert-sdd-creator/references/expert-structure.md b/skills/sdd/expert-sdd-creator/references/expert-structure.md deleted file mode 100644 index c550bc6..0000000 --- a/skills/sdd/expert-sdd-creator/references/expert-structure.md +++ /dev/null @@ -1,231 +0,0 @@ -# Expert Structure Guide - -Reference for creating well-structured SDD experts. - -## Directory Layout - -``` -expert-{name}/ -├── SKILL.md # Required: main entry point -├── references/ # Required: domain knowledge -│ ├── {topic-1}.md -│ ├── {topic-N}.md -│ └── signal-workflow.md # Required: signal documentation -└── scripts/ # Required: signal scripts - ├── run_signal.sh # Required: main signal entry - └── {helpers}.sh # Optional: additional scripts -``` - ---- - -## SKILL.md Structure - -### Frontmatter (YAML) - -```yaml ---- -name: expert-{name} -description: {domain} expertise with signal capability. {1-2 sentences about what it provides}. Use for {use cases}. Triggers: {comma-separated triggers} (project) ---- -``` - -**Rules:** -- `name` must be `expert-` prefix + kebab-case name -- `description` must include triggers for auto-discovery -- `description` must end with `(project)` -- Triggers should be comprehensive but not overly broad - -### Body Structure - -```markdown -# {Expert Name} - -{One-line description} - -## Quick Reference - -| Topic | Reference | Mode | -|-------|-----------|------| -| {topic} | `{file}.md` | Expert | -| Signal Workflow | `signal-workflow.md` | Signal | - ---- - -## Expert Mode - -**Use during:** Spec planning, learning, implementation guidance - -### Quick Navigation - -- **{Category}?** → `{file}.md` - {description} - ---- - -## Signal Mode - -**Use during:** Implementation phase (after spec exists) - -### Quick Commands - -| Action | Command | -|--------|---------| -| {action} | `scripts/{script}.sh {args}` | - -→ See `references/signal-workflow.md` for detailed workflow -``` - ---- - -## Reference Files - -### Organization Principles - -1. **One topic per file** - keep files focused -2. **Practical over theoretical** - include examples -3. **Scannable structure** - use headers, tables, code blocks -4. **Link between files** - reference related content - -### Required: signal-workflow.md - -Every expert must have `references/signal-workflow.md` containing: - -```markdown -# {Expert} Signal Workflow - -**Use during:** Implementation phase -**NOT for:** Spec planning or general questions - -## Workflow Overview - -{Diagram or description of feedback loop} - -## Signal Scripts - -| Script | Purpose | -|--------|---------| -| `run_signal.sh` | {main purpose} | -| `{helper}.sh` | {purpose} | - -## Script Usage - -### {Script Name} - -```bash -scripts/{script}.sh {args} -``` - -{Description of what it does} - -## Interpreting Results - -### Success -{What success looks like} - -### Failure -{What failure looks like and how to fix} -``` - ---- - -## Scripts - -### run_signal.sh Requirements - -1. **Shebang**: `#!/bin/bash` -2. **Strict mode**: `set -euo pipefail` -3. **Usage info**: Show help when called incorrectly -4. **Structured output**: JSON or clearly formatted for AI parsing -5. **Exit codes**: 0=success, non-zero=failure - -### Template Structure - -```bash -#!/bin/bash -# run_signal.sh - {Expert} signal verification -# -# Usage: run_signal.sh [options] -# -# Options: -# --option1 Description -# --verbose Show detailed output - -set -euo pipefail - -# Parse arguments -if [[ $# -lt 1 ]]; then - echo "Usage: run_signal.sh [options]" - exit 1 -fi - -# Main logic -{domain-specific checks} - -# Output results -echo "{" -echo " \"status\": \"$STATUS\"," -echo " \"details\": \"$DETAILS\"" -echo "}" - -exit $EXIT_CODE -``` - ---- - -## Naming Conventions - -| Item | Convention | Example | -|------|------------|---------| -| Expert directory | `expert-{domain}` | `expert-migrations` | -| Reference files | `{topic}.md` (kebab-case) | `rollback-strategies.md` | -| Signal workflow | `signal-workflow.md` | Always this name | -| Main signal script | `run_signal.sh` | Always this name | -| Helper scripts | `{verb}_{noun}.sh` | `parse_results.sh` | - ---- - -## Common Patterns - -### Expert for Testing Domain - -``` -expert-{test-framework}/ -├── SKILL.md -├── references/ -│ ├── test-patterns.md -│ ├── configuration.md -│ ├── troubleshooting.md -│ └── signal-workflow.md -└── scripts/ - ├── run_signal.sh # Runs tests - └── parse_results.sh # Parses test output -``` - -### Expert for API/Service Domain - -``` -expert-{service}/ -├── SKILL.md -├── references/ -│ ├── endpoint-patterns.md -│ ├── authentication.md -│ ├── error-handling.md -│ └── signal-workflow.md -└── scripts/ - ├── run_signal.sh # Calls endpoints - └── check_health.sh # Health checks -``` - -### Expert for Tool/CLI Domain - -``` -expert-{tool}/ -├── SKILL.md -├── references/ -│ ├── commands.md -│ ├── configuration.md -│ ├── best-practices.md -│ └── signal-workflow.md -└── scripts/ - ├── run_signal.sh # Runs tool commands - └── parse_output.sh # Parses CLI output -``` diff --git a/skills/sdd/expert-sdd-creator/references/signal-patterns.md b/skills/sdd/expert-sdd-creator/references/signal-patterns.md deleted file mode 100644 index b0c4380..0000000 --- a/skills/sdd/expert-sdd-creator/references/signal-patterns.md +++ /dev/null @@ -1,367 +0,0 @@ -# Signal Script Patterns - -Common patterns for generating signal scripts based on domain type. - ---- - -## Pattern Selection - -| Domain Keywords | Pattern | Primary Check | -|-----------------|---------|---------------| -| test, cucumber, junit, karate | Testing | Run tests, parse results | -| api, rest, endpoint, http, graphql | API/Service | Call endpoints, check responses | -| build, maven, gradle, npm | Build | Run build, check artifacts | -| config, yaml, json, properties | Config/Data | Validate syntax | -| cli, flyway, kubectl, terraform | CLI Tool | Run commands, parse output | - ---- - -## Testing Pattern - -For test frameworks (Cucumber, JUnit, Karate). - -### run_signal.sh - -```bash -#!/bin/bash -# run_signal.sh - Test execution signal -# -# Usage: run_signal.sh [--environment ] [--tags ] - -set -euo pipefail - -ENVIRONMENT="${1:-local}" -TAGS="${2:-}" - -echo "═══════════════════════════════════════════════════════════════" -echo "TEST SIGNAL" -echo "═══════════════════════════════════════════════════════════════" -echo "" -echo "Environment: $ENVIRONMENT" -echo "Tags: ${TAGS:-all}" -echo "" - -# TODO: Replace with actual test command -# Examples: -# mvn test -Dcucumber.filter.tags="$TAGS" -# ./gradlew test -# customCli run test --environment "$ENVIRONMENT" -echo "Running tests..." -TEST_OUTPUT=$(mvn test 2>&1) || TEST_EXIT=$? -TEST_EXIT=${TEST_EXIT:-0} - -# Parse results -# TODO: Adjust parsing based on test framework -TESTS_RUN=$(echo "$TEST_OUTPUT" | grep -oP 'Tests run: \K\d+' | tail -1 || echo "0") -FAILURES=$(echo "$TEST_OUTPUT" | grep -oP 'Failures: \K\d+' | tail -1 || echo "0") -ERRORS=$(echo "$TEST_OUTPUT" | grep -oP 'Errors: \K\d+' | tail -1 || echo "0") - -echo "" -echo "═══════════════════════════════════════════════════════════════" -echo "RESULTS" -echo "═══════════════════════════════════════════════════════════════" -echo "" -echo "{" -echo " \"tests_run\": $TESTS_RUN," -echo " \"failures\": $FAILURES," -echo " \"errors\": $ERRORS," -echo " \"status\": \"$([ $TEST_EXIT -eq 0 ] && echo PASS || echo FAIL)\"" -echo "}" - -exit $TEST_EXIT -``` - ---- - -## API/Service Pattern - -For REST APIs, GraphQL, HTTP services. - -### run_signal.sh - -```bash -#!/bin/bash -# run_signal.sh - API endpoint signal check -# -# Usage: run_signal.sh [--method ] [--data ] - -set -euo pipefail - -if [[ $# -lt 2 ]]; then - echo "Usage: run_signal.sh [options]" - exit 1 -fi - -BASE_URL="$1" -ENDPOINT="$2" -METHOD="${3:-GET}" -DATA="${4:-}" - -echo "═══════════════════════════════════════════════════════════════" -echo "API SIGNAL CHECK" -echo "═══════════════════════════════════════════════════════════════" -echo "" -echo "URL: ${BASE_URL}${ENDPOINT}" -echo "Method: $METHOD" -echo "" - -# Build curl command -CURL_CMD=(curl -s -w "\n%{http_code}\n%{time_total}" -X "$METHOD") -CURL_CMD+=(-H "Accept: application/json") -CURL_CMD+=(-H "Content-Type: application/json") - -if [[ -n "$DATA" ]]; then - CURL_CMD+=(-d "$DATA") -fi - -CURL_CMD+=("${BASE_URL}${ENDPOINT}") - -# Execute request -RESPONSE=$("${CURL_CMD[@]}" 2>&1) || true - -# Parse response -BODY=$(echo "$RESPONSE" | head -n -2) -HTTP_CODE=$(echo "$RESPONSE" | tail -2 | head -1) -TIME_TOTAL=$(echo "$RESPONSE" | tail -1) - -# Determine status -if [[ "$HTTP_CODE" =~ ^2 ]]; then - STATUS="SUCCESS" - EXIT_CODE=0 -elif [[ "$HTTP_CODE" =~ ^4 ]]; then - STATUS="CLIENT_ERROR" - EXIT_CODE=4 -else - STATUS="SERVER_ERROR" - EXIT_CODE=1 -fi - -echo "═══════════════════════════════════════════════════════════════" -echo "RESULTS" -echo "═══════════════════════════════════════════════════════════════" -echo "" -echo "{" -echo " \"http_status\": $HTTP_CODE," -echo " \"response_time_seconds\": $TIME_TOTAL," -echo " \"status\": \"$STATUS\"" -echo "}" -echo "" -echo "Response Body:" -echo "$BODY" | head -c 500 - -exit $EXIT_CODE -``` - ---- - -## Build Pattern - -For build tools (Maven, Gradle, npm). - -### run_signal.sh - -```bash -#!/bin/bash -# run_signal.sh - Build verification signal -# -# Usage: run_signal.sh [--skip-tests] - -set -euo pipefail - -SKIP_TESTS="${1:-}" - -echo "═══════════════════════════════════════════════════════════════" -echo "BUILD SIGNAL" -echo "═══════════════════════════════════════════════════════════════" -echo "" - -# TODO: Replace with actual build command -# Examples: -# mvn clean package -DskipTests -# ./gradlew build -# npm run build -BUILD_CMD="mvn clean package" -if [[ "$SKIP_TESTS" == "--skip-tests" ]]; then - BUILD_CMD="$BUILD_CMD -DskipTests" -fi - -echo "Running: $BUILD_CMD" -echo "" - -BUILD_OUTPUT=$($BUILD_CMD 2>&1) || BUILD_EXIT=$? -BUILD_EXIT=${BUILD_EXIT:-0} - -# Check for artifacts -# TODO: Adjust artifact path -ARTIFACT_PATH="target/*.jar" -ARTIFACT_COUNT=$(ls $ARTIFACT_PATH 2>/dev/null | wc -l || echo "0") - -echo "" -echo "═══════════════════════════════════════════════════════════════" -echo "RESULTS" -echo "═══════════════════════════════════════════════════════════════" -echo "" -echo "{" -echo " \"build_status\": \"$([ $BUILD_EXIT -eq 0 ] && echo SUCCESS || echo FAILED)\"," -echo " \"artifacts_found\": $ARTIFACT_COUNT" -echo "}" - -exit $BUILD_EXIT -``` - ---- - -## CLI Tool Pattern - -For command-line tools (flyway, kubectl, terraform). - -### run_signal.sh - -```bash -#!/bin/bash -# run_signal.sh - CLI tool signal check -# -# Usage: run_signal.sh [args...] - -set -euo pipefail - -if [[ $# -lt 1 ]]; then - echo "Usage: run_signal.sh [args...]" - exit 1 -fi - -COMMAND="$1" -shift -ARGS="$*" - -echo "═══════════════════════════════════════════════════════════════" -echo "CLI SIGNAL" -echo "═══════════════════════════════════════════════════════════════" -echo "" -echo "Command: $COMMAND $ARGS" -echo "" - -# Execute command -# TODO: Replace with actual CLI invocation -OUTPUT=$($COMMAND $ARGS 2>&1) || EXIT_CODE=$? -EXIT_CODE=${EXIT_CODE:-0} - -echo "Output:" -echo "$OUTPUT" -echo "" - -echo "═══════════════════════════════════════════════════════════════" -echo "RESULTS" -echo "═══════════════════════════════════════════════════════════════" -echo "" -echo "{" -echo " \"command\": \"$COMMAND $ARGS\"," -echo " \"exit_code\": $EXIT_CODE," -echo " \"status\": \"$([ $EXIT_CODE -eq 0 ] && echo SUCCESS || echo FAILED)\"" -echo "}" - -exit $EXIT_CODE -``` - ---- - -## Config Validation Pattern - -For configuration files (YAML, JSON, properties). - -### run_signal.sh - -```bash -#!/bin/bash -# run_signal.sh - Config validation signal -# -# Usage: run_signal.sh - -set -euo pipefail - -if [[ $# -lt 1 ]]; then - echo "Usage: run_signal.sh " - exit 1 -fi - -CONFIG_FILE="$1" - -echo "═══════════════════════════════════════════════════════════════" -echo "CONFIG VALIDATION SIGNAL" -echo "═══════════════════════════════════════════════════════════════" -echo "" -echo "File: $CONFIG_FILE" -echo "" - -# Check file exists -if [[ ! -f "$CONFIG_FILE" ]]; then - echo "ERROR: File not found" - exit 1 -fi - -# Validate based on extension -EXT="${CONFIG_FILE##*.}" -VALID=true -ERROR_MSG="" - -case "$EXT" in - yaml|yml) - # TODO: Use yq or python for validation - if command -v python3 &> /dev/null; then - python3 -c "import yaml; yaml.safe_load(open('$CONFIG_FILE'))" 2>&1 || { - VALID=false - ERROR_MSG="Invalid YAML syntax" - } - fi - ;; - json) - if command -v jq &> /dev/null; then - jq . "$CONFIG_FILE" > /dev/null 2>&1 || { - VALID=false - ERROR_MSG="Invalid JSON syntax" - } - elif command -v python3 &> /dev/null; then - python3 -c "import json; json.load(open('$CONFIG_FILE'))" 2>&1 || { - VALID=false - ERROR_MSG="Invalid JSON syntax" - } - fi - ;; - *) - echo "Warning: Unknown extension, skipping syntax check" - ;; -esac - -echo "═══════════════════════════════════════════════════════════════" -echo "RESULTS" -echo "═══════════════════════════════════════════════════════════════" -echo "" -echo "{" -echo " \"file\": \"$CONFIG_FILE\"," -echo " \"valid\": $VALID," -echo " \"error\": \"$ERROR_MSG\"" -echo "}" - -$VALID && exit 0 || exit 1 -``` - ---- - -## Output Format - -All signal scripts should output structured JSON for AI parsing: - -```json -{ - "status": "SUCCESS|FAILED|ERROR", - "details": "Human-readable summary", - "metrics": { - "key": "value" - } -} -``` - -Exit codes: -- `0` = Success -- `1` = Failure (generic) -- `4` = Client error (for API patterns) diff --git a/skills/sdd/expert-sdd-creator/scripts/register_expert.sh b/skills/sdd/expert-sdd-creator/scripts/register_expert.sh deleted file mode 100755 index 71ea4a9..0000000 --- a/skills/sdd/expert-sdd-creator/scripts/register_expert.sh +++ /dev/null @@ -1,262 +0,0 @@ -#!/bin/bash -# register_expert.sh - Register expert in experts.md and signals.md catalogs -# -# Usage: register_expert.sh [--dry-run] -# -# Parses expert metadata from SKILL.md and inserts entries into: -# - .claude/skills/spec-planning/references/experts.md (resolved via SKILLS_BASE) -# - .claude/skills/spec-planning/references/signals.md (resolved via SKILLS_BASE) -# -# Exit codes: -# 0 = Success -# 1 = Error - -set -euo pipefail - -# Colors -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -if [[ $# -lt 1 ]]; then - echo "Usage: register_expert.sh [--dry-run]" - exit 1 -fi - -EXPERT_DIR="$1" -DRY_RUN=false - -if [[ "${2:-}" == "--dry-run" ]]; then - DRY_RUN=true -fi - -# Derive skills base from script location. -# Script is at: .claude/skills/expert-sdd-creator/scripts/register_expert.sh -# Skills base (.claude/skills/) is 2 directories up from SCRIPT_DIR. -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -SKILLS_BASE="$(cd "$SCRIPT_DIR/../.." && pwd)" - -if [[ ! -d "$SKILLS_BASE/spec-planning" ]]; then - echo -e "${RED}ERROR:${NC} Could not locate spec-planning skill." - echo " Expected at: $SKILLS_BASE/spec-planning/" - echo " Install it with: npx skills add " - exit 1 -fi - -EXPERTS_MD="$SKILLS_BASE/spec-planning/references/experts.md" -SIGNALS_MD="$SKILLS_BASE/spec-planning/references/signals.md" - -echo "═══════════════════════════════════════════════════════════════" -echo "EXPERT REGISTRATION" -echo "═══════════════════════════════════════════════════════════════" -echo "" -echo "Expert directory: $EXPERT_DIR" -echo "Experts catalog: $EXPERTS_MD" -echo "Signals catalog: $SIGNALS_MD" -if $DRY_RUN; then - echo -e "${YELLOW}Mode: DRY RUN (no changes will be made)${NC}" -fi -echo "" - -# Check expert directory exists -if [[ ! -d "$EXPERT_DIR" ]]; then - echo -e "${RED}ERROR:${NC} Expert directory not found: $EXPERT_DIR" - exit 1 -fi - -# Check SKILL.md exists -if [[ ! -f "$EXPERT_DIR/SKILL.md" ]]; then - echo -e "${RED}ERROR:${NC} SKILL.md not found in $EXPERT_DIR" - exit 1 -fi - -# Check catalog files exist -if [[ ! -f "$EXPERTS_MD" ]]; then - echo -e "${RED}ERROR:${NC} Experts catalog not found: $EXPERTS_MD" - exit 1 -fi -if [[ ! -f "$SIGNALS_MD" ]]; then - echo -e "${RED}ERROR:${NC} Signals catalog not found: $SIGNALS_MD" - exit 1 -fi - -# Parse SKILL.md frontmatter -echo "Parsing SKILL.md..." - -# Extract frontmatter -FRONTMATTER=$(sed -n '/^---$/,/^---$/p' "$EXPERT_DIR/SKILL.md" | sed '1d;$d') - -# Extract name -EXPERT_NAME=$(echo "$FRONTMATTER" | grep "^name:" | sed 's/name: *//') -if [[ -z "$EXPERT_NAME" ]]; then - echo -e "${RED}ERROR:${NC} Could not extract 'name' from frontmatter" - exit 1 -fi - -# Extract description -DESCRIPTION=$(echo "$FRONTMATTER" | grep "^description:" | sed 's/description: *//') -if [[ -z "$DESCRIPTION" ]]; then - echo -e "${RED}ERROR:${NC} Could not extract 'description' from frontmatter" - exit 1 -fi - -# Extract triggers from description (after "Triggers:") -TRIGGERS="" -if echo "$DESCRIPTION" | grep -q "Triggers:"; then - TRIGGERS=$(echo "$DESCRIPTION" | sed 's/.*Triggers: *//' | sed 's/ *(project).*//') -fi - -echo " Name: $EXPERT_NAME" -echo " Description: ${DESCRIPTION:0:60}..." -echo " Triggers: ${TRIGGERS:0:60}..." -echo "" - -# Check if expert already registered -if grep -q "### [0-9]*\. $EXPERT_NAME$" "$EXPERTS_MD"; then - echo -e "${YELLOW}WARNING:${NC} Expert '$EXPERT_NAME' already exists in experts.md" - echo "Skipping registration to avoid duplicates." - exit 0 -fi - -# Count existing entries to determine next number -LAST_NUM=$(grep '### [0-9]*\.' "$EXPERTS_MD" | sed 's/### \([0-9]*\)\..*/\1/' | tail -1) -if [[ -z "$LAST_NUM" ]]; then - LAST_NUM=0 -fi -NEXT_NUM=$((LAST_NUM + 1)) - -echo "Next entry number: $NEXT_NUM" -echo "" - -# Get reference files for "What It Provides" -PROVIDES="" -if [[ -d "$EXPERT_DIR/references" ]]; then - for ref in "$EXPERT_DIR/references"/*.md; do - if [[ -f "$ref" && "$(basename "$ref")" != "signal-workflow.md" ]]; then - # Convert filename to readable form - TOPIC=$(basename "$ref" .md | tr '-' ' ' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) substr($i,2)}1') - PROVIDES="${PROVIDES}- ${TOPIC} guidance\n" - fi - done -fi - -# Generate experts.md entry -read -r -d '' EXPERTS_ENTRY << EOF || true - -### ${NEXT_NUM}. ${EXPERT_NAME} - -**Description:** ${DESCRIPTION%% Triggers:*} - -**Triggers:** -$(echo "$TRIGGERS" | tr ',' '\n' | sed 's/^ */- /') - -**What It Provides:** -$(echo -e "$PROVIDES") -**Signal Capability:** -- Runtime validation (see signal-workflow.md) - -**Skill Name:** \`${EXPERT_NAME}\` - ---- -EOF - -# Generate signals.md entry -read -r -d '' SIGNALS_ENTRY << EOF || true - -### ${NEXT_NUM}. ${EXPERT_NAME} (with signal capability) - -**Description:** Runtime validation for ${EXPERT_NAME#expert-} domain - -**Triggers:** -$(echo "$TRIGGERS" | tr ',' '\n' | sed 's/^ */- /') -- signal, verify, validate - -**What It Validates:** -- Domain-specific behavior validation -- See references/signal-workflow.md for details - -**How to Invoke:** \`skill: "${EXPERT_NAME}"\` - -**Typical Expected Behaviors:** -- Signal scripts return exit code 0 -- Validation checks pass - -**Typical Failure Indicators:** -- Signal scripts return non-zero exit code -- Validation errors in output - -**Skill Name:** \`${EXPERT_NAME}\` - ---- -EOF - -echo "═══════════════════════════════════════════════════════════════" -echo "ENTRIES TO ADD" -echo "═══════════════════════════════════════════════════════════════" -echo "" -echo -e "${BLUE}experts.md entry:${NC}" -echo "$EXPERTS_ENTRY" -echo "" -echo -e "${BLUE}signals.md entry:${NC}" -echo "$SIGNALS_ENTRY" -echo "" - -if $DRY_RUN; then - echo "═══════════════════════════════════════════════════════════════" - echo -e "${YELLOW}DRY RUN - No changes made${NC}" - echo "═══════════════════════════════════════════════════════════════" - echo "" - echo "To apply changes, run without --dry-run flag" - exit 0 -fi - -# Find insertion point in experts.md (before "## Example:") -echo "Inserting into experts.md..." -# Find line number of "## Example:" section -EXPERTS_INSERT_LINE=$(grep -n "^## Example:" "$EXPERTS_MD" | head -1 | cut -d: -f1) -if [[ -z "$EXPERTS_INSERT_LINE" ]]; then - # If no Example section, append to end - echo "$EXPERTS_ENTRY" >> "$EXPERTS_MD" - EXPERTS_INSERT_LINE="end" -else - # Insert before Example section - EXPERTS_INSERT_LINE=$((EXPERTS_INSERT_LINE - 1)) - # Create temp file with insertion - head -n "$EXPERTS_INSERT_LINE" "$EXPERTS_MD" > "$EXPERTS_MD.tmp" - echo "$EXPERTS_ENTRY" >> "$EXPERTS_MD.tmp" - tail -n +"$((EXPERTS_INSERT_LINE + 1))" "$EXPERTS_MD" >> "$EXPERTS_MD.tmp" - mv "$EXPERTS_MD.tmp" "$EXPERTS_MD" -fi -echo -e " ${GREEN}Done${NC} (inserted at line $EXPERTS_INSERT_LINE)" - -# Find insertion point in signals.md (before "## How to Use") -echo "Inserting into signals.md..." -SIGNALS_INSERT_LINE=$(grep -n "^## How to Use" "$SIGNALS_MD" | head -1 | cut -d: -f1) -if [[ -z "$SIGNALS_INSERT_LINE" ]]; then - # If no How to Use section, append to end - echo "$SIGNALS_ENTRY" >> "$SIGNALS_MD" - SIGNALS_INSERT_LINE="end" -else - # Insert before How to Use section - SIGNALS_INSERT_LINE=$((SIGNALS_INSERT_LINE - 1)) - # Create temp file with insertion - head -n "$SIGNALS_INSERT_LINE" "$SIGNALS_MD" > "$SIGNALS_MD.tmp" - echo "$SIGNALS_ENTRY" >> "$SIGNALS_MD.tmp" - tail -n +"$((SIGNALS_INSERT_LINE + 1))" "$SIGNALS_MD" >> "$SIGNALS_MD.tmp" - mv "$SIGNALS_MD.tmp" "$SIGNALS_MD" -fi -echo -e " ${GREEN}Done${NC} (inserted at line $SIGNALS_INSERT_LINE)" - -echo "" -echo "═══════════════════════════════════════════════════════════════" -echo -e "${GREEN}REGISTRATION COMPLETE${NC}" -echo "═══════════════════════════════════════════════════════════════" -echo "" -echo "{" -echo " \"expert\": \"$EXPERT_NAME\"," -echo " \"status\": \"REGISTERED\"," -echo " \"experts_md_line\": \"$EXPERTS_INSERT_LINE\"," -echo " \"signals_md_line\": \"$SIGNALS_INSERT_LINE\"" -echo "}" diff --git a/skills/sdd/expert-sdd-creator/scripts/validate_expert.sh b/skills/sdd/expert-sdd-creator/scripts/validate_expert.sh deleted file mode 100755 index 119ee7f..0000000 --- a/skills/sdd/expert-sdd-creator/scripts/validate_expert.sh +++ /dev/null @@ -1,202 +0,0 @@ -#!/bin/bash -# validate_expert.sh - Validate expert directory structure -# -# Usage: validate_expert.sh -# -# Validates: -# - Directory structure (SKILL.md, references/, scripts/) -# - YAML frontmatter (name, description) -# - References directory has files -# - signal-workflow.md exists -# - scripts/run_signal.sh exists and is executable -# -# Exit codes: -# 0 = Valid -# 1 = Invalid - -set -euo pipefail - -# Colors -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' - -if [[ $# -lt 1 ]]; then - echo "Usage: validate_expert.sh " - exit 1 -fi - -EXPERT_DIR="$1" -ERRORS=0 -WARNINGS=0 - -echo "═══════════════════════════════════════════════════════════════" -echo "EXPERT VALIDATION" -echo "═══════════════════════════════════════════════════════════════" -echo "" -echo "Directory: $EXPERT_DIR" -echo "" - -# Check directory exists -if [[ ! -d "$EXPERT_DIR" ]]; then - echo -e "${RED}[FAIL]${NC} Directory does not exist: $EXPERT_DIR" - exit 1 -fi - -# Extract expert name from directory -EXPERT_NAME=$(basename "$EXPERT_DIR") - -echo "Validating: $EXPERT_NAME" -echo "" - -# 1. Check SKILL.md exists -echo -n "[1/7] SKILL.md exists: " -if [[ -f "$EXPERT_DIR/SKILL.md" ]]; then - echo -e "${GREEN}PASS${NC}" -else - echo -e "${RED}FAIL${NC}" - ((ERRORS++)) -fi - -# 2. Check YAML frontmatter -echo -n "[2/7] Valid YAML frontmatter: " -if [[ -f "$EXPERT_DIR/SKILL.md" ]]; then - # Extract frontmatter (between --- markers) - FRONTMATTER=$(sed -n '/^---$/,/^---$/p' "$EXPERT_DIR/SKILL.md" | sed '1d;$d') - - # Check for name field - if echo "$FRONTMATTER" | grep -q "^name:"; then - # Check for description field - if echo "$FRONTMATTER" | grep -q "^description:"; then - echo -e "${GREEN}PASS${NC}" - else - echo -e "${RED}FAIL${NC} - missing 'description' field" - ((ERRORS++)) - fi - else - echo -e "${RED}FAIL${NC} - missing 'name' field" - ((ERRORS++)) - fi -else - echo -e "${YELLOW}SKIP${NC} - SKILL.md not found" -fi - -# 3. Check name matches directory -echo -n "[3/7] Name matches directory: " -if [[ -f "$EXPERT_DIR/SKILL.md" ]]; then - SKILL_NAME=$(sed -n '/^---$/,/^---$/p' "$EXPERT_DIR/SKILL.md" | grep "^name:" | sed 's/name: *//') - if [[ "$SKILL_NAME" == "$EXPERT_NAME" ]]; then - echo -e "${GREEN}PASS${NC}" - else - echo -e "${YELLOW}WARN${NC} - name '$SKILL_NAME' != directory '$EXPERT_NAME'" - ((WARNINGS++)) - fi -else - echo -e "${YELLOW}SKIP${NC}" -fi - -# 4. Check references/ directory -echo -n "[4/7] references/ directory: " -if [[ -d "$EXPERT_DIR/references" ]]; then - REF_COUNT=$(find "$EXPERT_DIR/references" -name "*.md" -type f | wc -l | tr -d ' ') - if [[ $REF_COUNT -gt 0 ]]; then - echo -e "${GREEN}PASS${NC} ($REF_COUNT files)" - else - echo -e "${RED}FAIL${NC} - no .md files in references/" - ((ERRORS++)) - fi -else - echo -e "${RED}FAIL${NC} - directory not found" - ((ERRORS++)) -fi - -# 5. Check signal-workflow.md exists -echo -n "[5/7] signal-workflow.md: " -if [[ -f "$EXPERT_DIR/references/signal-workflow.md" ]]; then - echo -e "${GREEN}PASS${NC}" -else - echo -e "${RED}FAIL${NC} - not found" - ((ERRORS++)) -fi - -# 6. Check scripts/ directory -echo -n "[6/7] scripts/ directory: " -if [[ -d "$EXPERT_DIR/scripts" ]]; then - echo -e "${GREEN}PASS${NC}" -else - echo -e "${RED}FAIL${NC} - directory not found" - ((ERRORS++)) -fi - -# 7. Check for executable signal scripts -echo -n "[7/7] Signal scripts: " -if [[ -d "$EXPERT_DIR/scripts" ]]; then - # Look for run_signal.sh or any *signal*.sh script - SIGNAL_SCRIPTS=$(find "$EXPERT_DIR/scripts" -name "*.sh" -type f \( -name "run_signal.sh" -o -name "*signal*.sh" \) 2>/dev/null || true) - if [[ -n "$SIGNAL_SCRIPTS" ]]; then - SCRIPT_NAME=$(basename "$(echo "$SIGNAL_SCRIPTS" | head -1)") - # Check if at least one is executable - EXECUTABLE_COUNT=0 - for script in $SIGNAL_SCRIPTS; do - if [[ -x "$script" ]]; then - ((EXECUTABLE_COUNT++)) - fi - done - if [[ $EXECUTABLE_COUNT -gt 0 ]]; then - echo -e "${GREEN}PASS${NC} ($SCRIPT_NAME)" - else - echo -e "${YELLOW}WARN${NC} - found but not executable" - ((WARNINGS++)) - fi - else - # Fallback: check for any .sh scripts - ANY_SCRIPTS=$(find "$EXPERT_DIR/scripts" -name "*.sh" -type f 2>/dev/null | head -1 || true) - if [[ -n "$ANY_SCRIPTS" ]]; then - SCRIPT_NAME=$(basename "$ANY_SCRIPTS") - echo -e "${YELLOW}WARN${NC} - found $SCRIPT_NAME (not named *signal*)" - ((WARNINGS++)) - else - echo -e "${RED}FAIL${NC} - no .sh scripts found" - ((ERRORS++)) - fi - fi -else - echo -e "${RED}FAIL${NC} - scripts/ not found" - ((ERRORS++)) -fi - -# Summary -echo "" -echo "═══════════════════════════════════════════════════════════════" -echo "SUMMARY" -echo "═══════════════════════════════════════════════════════════════" -echo "" - -if [[ $ERRORS -eq 0 ]]; then - echo -e "${GREEN}VALID${NC} - Expert structure is valid" - if [[ $WARNINGS -gt 0 ]]; then - echo -e "${YELLOW}$WARNINGS warning(s)${NC}" - fi - echo "" - echo "{" - echo " \"expert\": \"$EXPERT_NAME\"," - echo " \"status\": \"VALID\"," - echo " \"errors\": $ERRORS," - echo " \"warnings\": $WARNINGS" - echo "}" - exit 0 -else - echo -e "${RED}INVALID${NC} - $ERRORS error(s) found" - if [[ $WARNINGS -gt 0 ]]; then - echo -e "${YELLOW}$WARNINGS warning(s)${NC}" - fi - echo "" - echo "{" - echo " \"expert\": \"$EXPERT_NAME\"," - echo " \"status\": \"INVALID\"," - echo " \"errors\": $ERRORS," - echo " \"warnings\": $WARNINGS" - echo "}" - exit 1 -fi From cf9a7d492c8e942eb590ae6c365f0e304d22efc3 Mon Sep 17 00:00:00 2001 From: Rico Date: Sun, 5 Jul 2026 13:03:51 -0500 Subject: [PATCH 06/14] Move dispatcher to tier 1: parameterized scripts, per-env state, exit-10 drain protocol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dispatcher family moves out of per-project installs into the harness repo (scripts/) and takes the environment as an argument: scripts/poll-and-dispatch.sh [env-name] scripts/learn-dispatch.sh [env-name] (was learn-tick.sh) - All env git ops go through 'git -C $ENV_PATH' against the developer's own clone (refs, fetches, pushes, sibling worktrees — never their working tree), so the host worktree and harness-tick.sh's sync-then-exec dance are deleted outright: the dispatcher no longer lives inside the repo it manages. - Runtime state (counters, stuck sentinels, session TSVs) relocates to /state//; the env keeps only its committed .harness/env. - flock moves from $0 (would contend across environments now that the script is shared) to a per-env state lock. - New exit contract: 0 = idle (incl. STUCK-only ticks), 10 = advanced (the supervisor re-invokes immediately to drain), else error (backoff). - gh calls go through ghe() so gh resolves the ENVIRONMENT repo from cwd. - Cleanup also deletes the local feature/* branch worktree-add created in the developer's clone. - The shim skills (poll-and-dispatch, learn-loop) die with harness-tick.sh: the CLI supervisor replaces the /loop startup path. Co-Authored-By: Claude Fable 5 --- .../assets => scripts}/harness-lib.sh | 58 +++-- .../learn-dispatch.sh | 111 +++++----- .../assets => scripts}/poll-and-dispatch.sh | 200 ++++++++++-------- .../harness-init/assets/harness-tick.sh | 38 ---- .../harness-init/assets/learn-loop-SKILL.md | 27 --- .../assets/poll-and-dispatch-SKILL.md | 23 -- 6 files changed, 213 insertions(+), 244 deletions(-) rename {skills/harness/harness-init/assets => scripts}/harness-lib.sh (52%) rename skills/harness/harness-init/assets/learn-tick.sh => scripts/learn-dispatch.sh (57%) mode change 100644 => 100755 rename {skills/harness/harness-init/assets => scripts}/poll-and-dispatch.sh (70%) delete mode 100755 skills/harness/harness-init/assets/harness-tick.sh delete mode 100644 skills/harness/harness-init/assets/learn-loop-SKILL.md delete mode 100644 skills/harness/harness-init/assets/poll-and-dispatch-SKILL.md diff --git a/skills/harness/harness-init/assets/harness-lib.sh b/scripts/harness-lib.sh similarity index 52% rename from skills/harness/harness-init/assets/harness-lib.sh rename to scripts/harness-lib.sh index d08d2b0..308ade8 100644 --- a/skills/harness/harness-init/assets/harness-lib.sh +++ b/scripts/harness-lib.sh @@ -2,49 +2,61 @@ # harness-lib.sh — shared helpers for the harness scripts. # # Sourced by BOTH scripts/poll-and-dispatch.sh (the feature/build loop) and -# scripts/learn-tick.sh (the memory loop). These are pure functions: they read -# globals the sourcing script defines (CLAUDE_PERM_ARGS, WORKTREE_BASE), and bash -# resolves those at call time — so the only requirement is that the caller sets -# its config block before it calls a helper, not before it sources this file. +# scripts/learn-dispatch.sh (the memory loop). These are pure functions: they +# read globals the sourcing script defines (ENV_PATH, STATE_DIR, +# CLAUDE_PERM_ARGS, WORKTREE_BASE), and bash resolves those at call time — so +# the only requirement is that the caller sets its config block before it calls +# a helper, not before it sources this file. # -# Generated by /harness-init. Keep this minimal — it exists only to avoid +# Tier 1 (harness repo) owned. Keep this minimal — it exists only to avoid # duplicating run_claude (and its session-id discipline) across two scripts. # Map a name (a feature, or the literal "learn") to its worktree path. Both loops -# create sibling worktrees off the same WORKTREE_BASE, derived from the MAIN -# worktree by the sourcing script: feature paths are '-harness-', -# the memory loop's is '-harness-learn'. (Inv 3) +# create sibling worktrees off the same WORKTREE_BASE, derived from the +# environment's path by the sourcing script: feature paths are +# '-harness-', the memory loop's is '-harness-learn'. (Inv 3) worktree_for() { echo "${WORKTREE_BASE}-$1"; } -# LOCAL ADDITION (not in the canonical design-doc dispatcher): make a freshly -# created worktree runnable. A bare worktree has no gitignored files -# (node_modules, .env, generated code), so signals, the PRD runner, and /learn's -# drafted-lint check would fail for reasons unrelated to the work. If the project -# has no bootstrap script, this is a no-op. +# Run gh in the ENVIRONMENT repo. gh resolves "which GitHub repo" from its cwd; +# the dispatcher's cwd is the harness repo, which is the WRONG repo — every gh +# call that skipped this wrapper would silently act on (or fail against) the +# harness repo, and the 2>/dev/null guards would hide it. +ghe() { (cd "$ENV_PATH" && gh "$@"); } + +# Make a freshly created worktree runnable. A bare worktree has no gitignored +# files (node_modules, .env, generated code — and the tier-1 skill symlinks), +# so signals, the PRD runner, and /learn's drafted-lint check would fail for +# reasons unrelated to the work. The script is the environment's own +# (project-owned, generated by /env-init); its deterministic header re-links the +# tier-1 skills via `context-specs link` before the project-specific +# provisioning. If the environment has no bootstrap script, this is a no-op. bootstrap_worktree() { local wt="$1" - if [[ -x scripts/bootstrap-worktree.sh ]]; then - ./scripts/bootstrap-worktree.sh "$wt" || \ + if [[ -x "$ENV_PATH/scripts/bootstrap-worktree.sh" ]]; then + "$ENV_PATH/scripts/bootstrap-worktree.sh" "$wt" || \ echo "WARN: bootstrap-worktree.sh failed for ${wt}" >&2 fi } # Wrap every claude -p call. Generates a session UUID, runs claude headless with # --session-id so the trace at ~/.claude/projects//.jsonl is -# locatable later, and appends a row to .harness/sessions-.tsv. The TSV -# is the per-feature (or per-learn-sha) audit trail the STUCK / learn-review -# signals point the human into. +# locatable later, and appends a row to $STATE_DIR/sessions-.tsv. The +# TSV is the per-feature (or per-learn-sha) audit trail the STUCK / learn-review +# signals point the human into. Every invocation counts as a transition for the +# build dispatcher's exit-10 drain protocol (guarded default — the memory loop +# sources this lib without a counter). run_claude() { local step="$1" feature="$2" attempt="$3" wt="$4"; shift 4 + TRANSITIONS=$(( ${TRANSITIONS:-0} + 1 )) local sid; sid="$(uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "noid-$$-$RANDOM")" - local log=".harness/sessions-${feature}.tsv" + local log="$STATE_DIR/sessions-${feature}.tsv" [[ -s "$log" ]] || printf '#timestamp\tstep\tattempt\tsession_id\texit\tduration_s\n' > "$log" local t0; t0="$(date +%s)" # No print-mode --cwd flag exists; `cd` is the only way to set the working # directory, and it's also what gives the skill its .claude/ command + AGENTS.md # / CLAUDE.md discovery inside the worktree. (Inv 3 + 6: the skill operates on - # its own worktree, never the loop's checkout.) The build loop passes the - # per-feature worktree; the memory loop passes the '-harness-learn' worktree. + # its own worktree, never the developer's checkout.) The build loop passes the + # per-feature worktree; the memory loop passes the '-harness-learn' worktree. # The `|| exit=$?` keeps a non-zero skill exit from tripping `set -e` so the row # below always gets written (the STUCK / learn-review dossier needs it), and # `return 0` keeps a failed step from aborting the rest of the tick — the absent @@ -64,9 +76,9 @@ run_claude() { # are surfaced on the PR in every terminal state. render_sessions_table() { local feature="$1" - [[ -f ".harness/sessions-${feature}.tsv" ]] || return 0 + [[ -f "$STATE_DIR/sessions-${feature}.tsv" ]] || return 0 echo '| Time | Step | Attempt | Session ID | Exit |' echo '|------|------|---------|------------|------|' - grep -v '^#' ".harness/sessions-${feature}.tsv" 2>/dev/null | tail -n 20 | \ + grep -v '^#' "$STATE_DIR/sessions-${feature}.tsv" 2>/dev/null | tail -n 20 | \ awk -F'\t' '{printf "| %s | `%s` | %s | `%s` | %s |\n", $1, $2, $3, $4, $5}' } diff --git a/skills/harness/harness-init/assets/learn-tick.sh b/scripts/learn-dispatch.sh old mode 100644 new mode 100755 similarity index 57% rename from skills/harness/harness-init/assets/learn-tick.sh rename to scripts/learn-dispatch.sh index 4726a59..4c680d7 --- a/skills/harness/harness-init/assets/learn-tick.sh +++ b/scripts/learn-dispatch.sh @@ -1,46 +1,55 @@ #!/usr/bin/env bash -# learn-tick.sh — one tick of the MEMORY loop. +# learn-dispatch.sh — one tick of the MEMORY loop for ONE environment. # -# The post-merge memory update (/learn) used to be step 5 of the dispatcher, -# running in the host worktree at cwd "." under the build loop's flock. That made a -# multi-minute memory rebuild block every feature step (and a live /learn froze the -# whole tick). This script makes the memory update its OWN loop: its own /loop -# session, its own flock, its own dedicated worktree. The two loops never block each -# other and coordinate only through git (Inv 1 + 7): +# The post-merge memory update (/learn) used to be a dispatcher step, which made +# a multi-minute memory rebuild block every feature step. This script makes the +# memory update its OWN loop: its own supervisor schedule, its own lock, its own +# dedicated worktree. The two loops never block each other and coordinate only +# through git (Inv 1 + 7): # - refs/harness/last-learned — a single moving "watermark" ref recording how far # into main's history /learn has already digested. It lives in its own ref # namespace, so it survives learn/ branch deletion and is shared across # nodes. We advance it with an atomic compare-and-swap (--force-with-lease). # - learn/ + `git ls-remote` — per-merge idempotency, exactly as before. # -# Run it on an interval from the harness HOST worktree, alongside the build loop: -# /loop 10m /learn-loop +# Tier 1 (harness repo) owned. Invoked by the context-specs CLI supervisor on its +# own interval (default 10m): # -# Generated by /harness-init. Safe to edit — see references/dispatcher-explained.md -# ("The memory loop") for the design and what is safe to change. - -# Serialize against concurrent learn ticks on this node (a from-scratch Expert -# bootstrap can outlast the tick interval). Independent of the dispatcher's flock — -# different file — so the two loops never wait on each other. (Inv 5) -exec {lockfd}<"$0"; flock -n $lockfd || exit 0 +# scripts/learn-dispatch.sh [env-name] +# +# Exit contract: 0 = no-op/paused/done, nonzero = error (supervisor backs off). +# There is no exit-10 drain here — after a learn run, the open learn/ PR +# pauses the loop until the human merges, so the next tick is a no-op anyway. +# +# See references/dispatcher-explained.md ("The memory loop") in +# skills/harness/env-init for the design and what is safe to change. set -euo pipefail -cd "$(dirname "${BASH_SOURCE[0]}")/.." # repo root of the host worktree (where /loop runs) -# Config the shared helpers need. Mirrors the dispatcher's block: derive WORKTREE_BASE -# from the MAIN worktree (always first in `git worktree list`), NOT $PWD, so the learn -# worktree path is '-harness-learn' even though we run from '-harness'. +CONTEXT_SPECS_HOME="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +export CONTEXT_SPECS_HOME +ENV_PATH="$(cd "${1:?usage: learn-dispatch.sh [env-name]}" && pwd)" +ENV_NAME="${2:-$(basename "$ENV_PATH")}" +STATE_DIR="${STATE_DIR:-$CONTEXT_SPECS_HOME/state/$ENV_NAME}" +mkdir -p "$STATE_DIR" + +# Serialize against concurrent learn ticks for THIS environment (a from-scratch +# Expert bootstrap can outlast the tick interval). Independent of the build +# loop's tick.lock — different file — so the two loops never wait on each +# other. (Inv 5) +exec {lockfd}>"$STATE_DIR/learn.lock"; flock -n "$lockfd" || exit 0 + +# Config the shared helpers need. Mirrors the dispatcher's block. # CLAUDE_PERM_ARGS must be set ABOVE the .harness/env source so env can replace it. -MAIN_WT="$(git worktree list --porcelain | sed -n '1s/^worktree //p')" -WORKTREE_BASE="../$(basename "${MAIN_WT:-$PWD}")-harness" +WORKTREE_BASE="$(dirname "$ENV_PATH")/$(basename "$ENV_PATH")-harness" CLAUDE_PERM_ARGS=( --permission-mode auto ) -[[ -f .harness/env ]] && source .harness/env -mkdir -p .harness +[[ -f "$ENV_PATH/.harness/env" ]] && source "$ENV_PATH/.harness/env" -# Shared helpers: worktree_for, bootstrap_worktree, run_claude, render_sessions_table. +# Shared helpers: worktree_for, bootstrap_worktree, run_claude, +# render_sessions_table, ghe. source "$(dirname "${BASH_SOURCE[0]}")/harness-lib.sh" -LEARN_WT="$(worktree_for learn)" # ../-harness-learn (persistent, reused) +LEARN_WT="$(worktree_for learn)" # -harness-learn sibling (persistent, reused) WATERMARK_REF="refs/harness/last-learned" # Post the headless session trail on the learn/ PR so the human evaluating the @@ -50,7 +59,7 @@ WATERMARK_REF="refs/harness/last-learned" # so the table shows exactly this run; $branch is learn/. signal_learn_review() { local feature="$1" branch="$2" - local body=".harness/learn-review-body-${feature}.md" + local body="$STATE_DIR/learn-review-body-${feature}.md" { echo "## /learn session — why memory changed" echo @@ -66,7 +75,7 @@ signal_learn_review() { echo render_sessions_table "$feature" } > "$body" - gh pr comment "$branch" --body-file "$body" 2>/dev/null || true + ghe pr comment "$branch" --body-file "$body" 2>/dev/null || true } # Atomic compare-and-swap on the watermark: move it to $TO only if the remote is @@ -76,29 +85,29 @@ signal_learn_review() { # dispatcher uses to claim PRDs. (Inv 7) advance_watermark() { local expect="${1:-0000000000000000000000000000000000000000}" - git push --quiet --force-with-lease="${WATERMARK_REF}:${expect}" \ + git -C "$ENV_PATH" push --quiet --force-with-lease="${WATERMARK_REF}:${expect}" \ origin "${TO}:${WATERMARK_REF}" 2>/dev/null \ - || echo "learn-tick: watermark not advanced (another node won the race, or push failed)" >&2 + || echo "learn-dispatch: watermark not advanced (another node won the race, or push failed)" >&2 } -# Fetch main + the watermark ref namespace. Safe from the host cwd — fetch only -# touches refs/objects, never the host *working tree* (that's the build loop's, synced -# by harness-tick.sh). Explicit refspecs because refs/harness/* isn't in the default. -git fetch --quiet origin \ +# Fetch main + the watermark ref namespace. Fetch only touches refs/objects, +# never the environment's working tree. Explicit refspecs because refs/harness/* +# isn't in the default. +git -C "$ENV_PATH" fetch --quiet origin \ '+refs/heads/*:refs/remotes/origin/*' \ '+refs/harness/*:refs/harness/*' || true # No remote / no main yet (e.g. a fresh-repo dry-run before origin exists) → nothing # to do. Guard before anything reads origin/main. -git rev-parse --verify --quiet origin/main >/dev/null 2>&1 \ - || { echo "learn-tick: no origin/main yet — nothing to do." >&2; exit 0; } +git -C "$ENV_PATH" rev-parse --verify --quiet origin/main >/dev/null 2>&1 \ + || { echo "learn-dispatch: no origin/main yet — nothing to do." >&2; exit 0; } # PAUSE while a learn PR is open: serialize memory edits behind human review so they # stay linear and conflict-free. Nothing is queued and nothing is dropped — the # backlog is implicit in (watermark, origin/main) and recomputed every tick. When the # human merges the open learn PR, the next tick batches every merge that landed since. # Checked early so a paused tick never even touches the learn worktree. -if gh pr list --state open --json headRefName \ +if ghe pr list --state open --json headRefName \ --jq '.[] | select(.headRefName | startswith("learn/")) | .headRefName' \ 2>/dev/null | grep -q .; then exit 0 @@ -107,21 +116,21 @@ fi # The diff range: from the durable watermark (or a bounded look-back on the very first # run — a full from-scratch Expert is /learn --rebuild, a human action, not this loop) # up to current main. -WATERMARK_OLD="$(git rev-parse --verify --quiet "${WATERMARK_REF}" 2>/dev/null || echo "")" +WATERMARK_OLD="$(git -C "$ENV_PATH" rev-parse --verify --quiet "${WATERMARK_REF}" 2>/dev/null || echo "")" if [[ -n "$WATERMARK_OLD" ]]; then SINCE="$WATERMARK_OLD" else - SINCE="$(git rev-parse --verify --quiet 'origin/main~50^{commit}' 2>/dev/null \ - || git rev-list --max-parents=0 origin/main | tail -n1)" + SINCE="$(git -C "$ENV_PATH" rev-parse --verify --quiet 'origin/main~50^{commit}' 2>/dev/null \ + || git -C "$ENV_PATH" rev-list --max-parents=0 origin/main | tail -n1)" fi -TO="$(git rev-parse origin/main)" +TO="$(git -C "$ENV_PATH" rev-parse origin/main)" # Nothing new on main → no-op (don't even touch the watermark or the worktree). [[ "$SINCE" == "$TO" ]] && exit 0 # Cross-node idempotency: if another node already pushed learn/, don't duplicate # it — just catch our watermark up and exit. (Inv 7) -if git ls-remote --exit-code origin "learn/${TO}" >/dev/null 2>&1; then +if git -C "$ENV_PATH" ls-remote --exit-code origin "learn/${TO}" >/dev/null 2>&1; then advance_watermark "$WATERMARK_OLD" exit 0 fi @@ -130,12 +139,15 @@ fi # is a clean, current main. Created once (with bootstrap, so a drafted lint and # check-agents-md.sh can actually run) and reused every run — there is exactly one, so # it's never torn down. `git worktree add` only writes the NEW path; it never touches -# the host working tree, so it can't race the build loop's host sync. +# the developer's working tree. if [[ ! -d "$LEARN_WT" ]]; then - git worktree add --quiet --detach "$LEARN_WT" origin/main \ - || { echo "learn-tick: could not create $LEARN_WT" >&2; exit 1; } + git -C "$ENV_PATH" worktree add --quiet --detach "$LEARN_WT" origin/main \ + || { echo "learn-dispatch: could not create $LEARN_WT" >&2; exit 1; } bootstrap_worktree "$LEARN_WT" fi +# The worktree is persistent but the tier-1 skill set is not frozen: re-link on +# every run so /learn always sees the current skills (idempotent, fast). +"$CONTEXT_SPECS_HOME/bin/context-specs" link "$LEARN_WT" >/dev/null 2>&1 || true # Per-run wipe (-fd keeps node_modules & bootstrapped deps, like the dispatcher's # per-feature wipe), then put it on the learn/ branch off the clean main. git -C "$LEARN_WT" checkout --quiet -f --detach origin/main @@ -148,16 +160,15 @@ run_claude learn "learn-${TO}" 1 "$LEARN_WT" "/learn --since ${SINCE} --sha ${TO # Surface this run's session on the learn PR (only if /learn actually opened one — a # 0/3 no-op merge teaches nothing and opens no PR). -if gh pr view "learn/${TO}" >/dev/null 2>&1; then +if ghe pr view "learn/${TO}" >/dev/null 2>&1; then signal_learn_review "learn-${TO}" "learn/${TO}" fi # Advance the watermark to TO whether or not a PR opened: a no-op merge is still -# "learned" and must not be re-examined every tick. (Same semantics as the old step-5 -# `last-main-sha` advance.) A deterministic /learn failure is not retried here — the -# recovery path is a human `/learn --rebuild`. +# "learned" and must not be re-examined every tick. A deterministic /learn failure +# is not retried here — the recovery path is a human `/learn --rebuild`. advance_watermark "$WATERMARK_OLD" # One-shot cleanup of this run's transient files — the session id now lives in the PR # comment, and the watermark + ls-remote prevent a re-run. -rm -f ".harness/sessions-learn-${TO}.tsv" ".harness/learn-review-body-learn-${TO}.md" +rm -f "$STATE_DIR/sessions-learn-${TO}.tsv" "$STATE_DIR/learn-review-body-learn-${TO}.md" diff --git a/skills/harness/harness-init/assets/poll-and-dispatch.sh b/scripts/poll-and-dispatch.sh similarity index 70% rename from skills/harness/harness-init/assets/poll-and-dispatch.sh rename to scripts/poll-and-dispatch.sh index aec3612..b2fd359 100755 --- a/skills/harness/harness-init/assets/poll-and-dispatch.sh +++ b/scripts/poll-and-dispatch.sh @@ -6,25 +6,46 @@ # Every section maps to one of the harness's load-bearing invariants — when this # script and the prose disagree, the invariants win. # -# Generated by /harness-init. Safe to edit — see the dispatcher-explained.md -# reference for what each section does and what is safe to change. - -# Serialize against concurrent ticks on this node (cron + /loop, etc.). (Inv 5) -exec {lockfd}<"$0"; flock -n $lockfd || exit 0 +# Tier 1 (harness repo) owned. Invoked by the context-specs CLI (`start`/`run`) +# with the target environment as an argument: +# +# scripts/poll-and-dispatch.sh [env-name] +# +# It operates on the environment repo via `git -C` (refs, fetches, pushes, and +# sibling worktrees — never the developer's working tree) and keeps all runtime +# state under /state//. Exit code contract: +# 0 — idle: no transitions this tick (includes STUCK-only ticks) +# 10 — advanced: at least one transition; the supervisor re-invokes immediately +# * — error: the supervisor backs off +# +# See the dispatcher-explained.md reference in skills/harness/env-init for what +# each section does and what is safe to change. set -euo pipefail -SLUG="$(git config user.email | cut -d@ -f1)" +CONTEXT_SPECS_HOME="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +export CONTEXT_SPECS_HOME # bootstrap-worktree.sh's link header consumes this +ENV_PATH="$(cd "${1:?usage: poll-and-dispatch.sh [env-name]}" && pwd)" +ENV_NAME="${2:-$(basename "$ENV_PATH")}" +STATE_DIR="${STATE_DIR:-$CONTEXT_SPECS_HOME/state/$ENV_NAME}" +mkdir -p "$STATE_DIR" +TRANSITIONS=0 + +# Serialize against concurrent ticks for THIS environment only. Per-env lock +# file, not $0 — the script is shared by every environment now. (Inv 5) +exec {lockfd}>"$STATE_DIR/tick.lock"; flock -n "$lockfd" || exit 0 + +# Reserve exit code 10 for the explicit "advanced" exit at the bottom: if a +# failing command happens to exit 10, report a plain error (1) so the supervisor +# backs off instead of hot-draining. +trap '[[ $? -eq 10 ]] && exit 1' ERR + +SLUG="$(git -C "$ENV_PATH" config user.email | cut -d@ -f1)" WATCH="${WATCH_PATTERN:-prd/${SLUG}/*}" -# Derive the repo name from the MAIN worktree (always listed first by -# `git worktree list`), NOT from $PWD: the dispatcher runs from the detached -# '-harness' HOST worktree, so basename "$PWD" would double the suffix to -# '-harness-harness'. Per Inv 3 each in-flight feature gets its own -# ephemeral worktree at '-harness-'; the host worktree stays put, -# detached at origin/main (re-synced each tick by scripts/harness-tick.sh). -# Overridable from .harness/env (sourced below). -MAIN_WT="$(git worktree list --porcelain | sed -n '1s/^worktree //p')" -WORKTREE_BASE="../$(basename "${MAIN_WT:-$PWD}")-harness" +# Per Inv 3 each in-flight feature gets its own ephemeral sibling worktree at +# '-harness-', hanging off the developer's own clone. Overridable +# from the env's committed .harness/env (sourced below). +WORKTREE_BASE="$(dirname "$ENV_PATH")/$(basename "$ENV_PATH")-harness" MAX_WORKTREES="${MAX_WORKTREES:-1}" PLANNING_CAP="${PLANNING_CAP:-2}" # /spec-planning retries before STUCK VALIDATE_CAP="${VALIDATE_CAP:-2}" # /spec-validate retries before STUCK @@ -39,7 +60,6 @@ FEEDBACK_CAP="${FEEDBACK_CAP:-5}" # reviewer feedback rounds before STUC # PR the human merges) — acceptable degradation, no special case. Set the marker # to EMPTY in .harness/env when there is no reviewer (converge at PR-open instead). REVIEW_CLEAN_MARKER="${REVIEW_CLEAN_MARKER:-HARNESS_REVIEW_CLEAN}" -mkdir -p .harness # Headless permission posture for `claude -p`. A headless session cannot show a # permission prompt — without a posture, tool calls are denied, the skill can't @@ -53,21 +73,21 @@ mkdir -p .harness # can replace the array. CLAUDE_PERM_ARGS=( --permission-mode auto ) -# Load project-local config if present (MAX_WORKTREES, WATCH_PATTERN, -# CLAUDE_PERM_ARGS, ...). -[[ -f .harness/env ]] && source .harness/env +# Load the environment's committed config if present (MAX_WORKTREES, +# WATCH_PATTERN, CLAUDE_PERM_ARGS, ...). +[[ -f "$ENV_PATH/.harness/env" ]] && source "$ENV_PATH/.harness/env" # Shared helpers (worktree_for, bootstrap_worktree, run_claude, -# render_sessions_table) live in harness-lib.sh — the memory loop (learn-tick.sh) -# uses the same ones, so they're factored out to avoid drift. They read the config -# globals set above (CLAUDE_PERM_ARGS) and below (WORKTREE_BASE); bash resolves -# those at call time. +# render_sessions_table, ghe) live in harness-lib.sh — the memory loop +# (learn-dispatch.sh) uses the same ones, so they're factored out to avoid drift. +# They read the config globals set above (ENV_PATH, STATE_DIR, CLAUDE_PERM_ARGS, +# WORKTREE_BASE); bash resolves those at call time. source "$(dirname "${BASH_SOURCE[0]}")/harness-lib.sh" # Invariant 2: a feature/ is harness-owned iff prds//prd.md is committed # to it. Hand-pushed feature/quickfix without a PRD is ignored. has_prd() { - git cat-file -e "origin/feature/${1}:prds/${1}/prd.md" 2>/dev/null + git -C "$ENV_PATH" cat-file -e "origin/feature/${1}:prds/${1}/prd.md" 2>/dev/null } # Convergence handoff: the reviewer reported no Important findings, so @@ -76,7 +96,7 @@ has_prd() { # Deterministic and once (the human-review-posted- marker prevents re-posting). signal_human_review() { local feature="$1" branch="feature/${feature}" - local body=".harness/human-review-body-${feature}.md" + local body="$STATE_DIR/human-review-body-${feature}.md" { echo "## Ready for your review" echo @@ -91,7 +111,7 @@ signal_human_review() { echo render_sessions_table "$feature" } > "$body" - gh pr comment "$branch" --body-file "$body" 2>/dev/null || true + ghe pr comment "$branch" --body-file "$body" 2>/dev/null || true } # Signal STUCK to the human via the PR. Opens a draft PR if none exists yet @@ -101,9 +121,9 @@ signal_human_review() { # the single human-facing surface; nothing else is captured to disk for the human. signal_stuck() { local feature="$1" step="$2" cap="$3" output_file="${4:-}" - touch ".harness/stuck-${feature}" + touch "$STATE_DIR/stuck-${feature}" local branch="feature/${feature}" - local body=".harness/stuck-body-${feature}.md" + local body="$STATE_DIR/stuck-body-${feature}.md" { echo "## STUCK — your turn" echo @@ -114,7 +134,7 @@ signal_stuck() { echo "the agent saw and concluded; for a CI/server harness, your project should" echo "upload these as workflow artifacts):" echo - if [[ -f ".harness/sessions-${feature}.tsv" ]]; then + if [[ -f "$STATE_DIR/sessions-${feature}.tsv" ]]; then render_sessions_table "$feature" echo fi @@ -138,10 +158,10 @@ signal_stuck() { echo "- [ ] Code fixed; \`./prds/${feature}/run-prd-test.sh\` passes locally" echo "- [ ] Ready to merge" } > "$body" - if gh pr view "$branch" >/dev/null 2>&1; then - gh pr comment "$branch" --body-file "$body" 2>/dev/null || true + if ghe pr view "$branch" >/dev/null 2>&1; then + ghe pr comment "$branch" --body-file "$body" 2>/dev/null || true else - gh pr create --base main --head "$branch" --draft \ + ghe pr create --base main --head "$branch" --draft \ --title "STUCK: ${feature} (${step})" --body-file "$body" 2>/dev/null || true fi } @@ -161,17 +181,17 @@ reviewer_converged() { # hid it, and this ALWAYS returned false — the HUMAN_REVIEW handoff never fired and # every PR ground to FEEDBACK_CAP and false-STUCK. Pull the comment bodies and # fixed-string match the marker in the shell instead. - gh pr view "$branch" --json comments --jq '.comments[]?.body' 2>/dev/null \ + ghe pr view "$branch" --json comments --jq '.comments[]?.body' 2>/dev/null \ | grep -qF "$REVIEW_CLEAN_MARKER" } -git fetch --quiet origin +git -C "$ENV_PATH" fetch --quiet origin # 1. Re-attach worktrees for in-flight feature/* that lost theirs. # In-flight work always continues regardless of MAX_WORKTREES — the cap is on # NEW intake, not continuation. Order is FIFO by remote branch committerdate. in_flight=() -for feature in $(git for-each-ref --sort=committerdate \ +for feature in $(git -C "$ENV_PATH" for-each-ref --sort=committerdate \ --format='%(refname:lstrip=4)' \ refs/remotes/origin/feature/ 2>/dev/null || true); do has_prd "$feature" || continue @@ -184,11 +204,11 @@ for feature in $(git for-each-ref --sort=committerdate \ # the local worktree. Empty state — no PR opened yet (pre-PR pipeline phase) or a # transient gh failure — is fail-SAFE: treat as in-flight and keep advancing, # never silently abandon live work. Merged is terminal, so this never rewinds. (Inv 9) - pr_state="$(gh pr view "feature/${feature}" --json state --jq .state 2>/dev/null || echo "")" + pr_state="$(ghe pr view "feature/${feature}" --json state --jq .state 2>/dev/null || echo "")" [[ "$pr_state" == "MERGED" || "$pr_state" == "CLOSED" ]] && continue wt="$(worktree_for "$feature")" if [[ ! -d "$wt" ]]; then - git worktree add "$wt" "feature/${feature}" 2>/dev/null && bootstrap_worktree "$wt" || true + git -C "$ENV_PATH" worktree add "$wt" "feature/${feature}" 2>/dev/null && bootstrap_worktree "$wt" || true fi [[ -d "$wt" ]] && in_flight+=("$feature") done @@ -199,19 +219,20 @@ done # Shared pool: set WATCH_PATTERN=prd/*/*. capacity=$(( MAX_WORKTREES - ${#in_flight[@]} )) if (( capacity > 0 )); then - for branch in $(git for-each-ref --sort=committerdate \ + for branch in $(git -C "$ENV_PATH" for-each-ref --sort=committerdate \ --format='%(refname:lstrip=3)' \ "refs/remotes/origin/${WATCH}" 2>/dev/null || true); do (( capacity > 0 )) || break feature="${branch##*/}" # Atomic rename = claim. Push failure (non-fast-forward) means another node # claimed first; skip silently. (Inv 2 + 7) - if git push origin "origin/${branch}:refs/heads/feature/${feature}" \ + if git -C "$ENV_PATH" push origin "origin/${branch}:refs/heads/feature/${feature}" \ ":refs/heads/${branch}" 2>/dev/null; then wt="$(worktree_for "$feature")" - git worktree add "$wt" "feature/${feature}" 2>/dev/null && bootstrap_worktree "$wt" || true + git -C "$ENV_PATH" worktree add "$wt" "feature/${feature}" 2>/dev/null && bootstrap_worktree "$wt" || true in_flight+=("$feature") capacity=$(( capacity - 1 )) + TRANSITIONS=$(( TRANSITIONS + 1 )) fi done fi @@ -226,17 +247,17 @@ for feature in ${in_flight[@]+"${in_flight[@]}"}; do # STUCK guard: a cap-hit handed this feature to the human via the PR. # Don't keep poking it — wait for merge/close (cleanup pass clears the # sentinel and the worktree). - [[ -f ".harness/stuck-${feature}" ]] && continue + [[ -f "$STATE_DIR/stuck-${feature}" ]] && continue # HUMAN_REVIEW guard: the reviewer converged and the PR was handed # to the human for /evaluate-pr. Halt — no advance — until the human merges or # closes (cleanup clears the sentinels + worktree). The human drives from here: # evaluate, then merge, close, or fix locally and push. The loop never re-engages. # Post the session trail exactly once (guarded by the -posted marker). - if [[ -f ".harness/human-review-${feature}" ]]; then - if [[ ! -f ".harness/human-review-posted-${feature}" ]]; then + if [[ -f "$STATE_DIR/human-review-${feature}" ]]; then + if [[ ! -f "$STATE_DIR/human-review-posted-${feature}" ]]; then signal_human_review "$feature" - touch ".harness/human-review-posted-${feature}" + touch "$STATE_DIR/human-review-posted-${feature}" fi continue fi @@ -259,7 +280,7 @@ for feature in ${in_flight[@]+"${in_flight[@]}"}; do # optional failing-output tail, and the diagnosis-first checklist. The stuck # sentinel above halts further advance until the human merges or closes. if [[ ! -f "${wt}/specs/${feature}/.planning-done" ]]; then - attempts_file=".harness/planning-attempts-${feature}" + attempts_file="$STATE_DIR/planning-attempts-${feature}" attempts=$(cat "${attempts_file}" 2>/dev/null || echo 0) if (( attempts >= PLANNING_CAP )); then echo "STUCK: ${feature} at /spec-planning (${PLANNING_CAP}x)." >&2 @@ -270,7 +291,7 @@ for feature in ${in_flight[@]+"${in_flight[@]}"}; do fi elif [[ ! -f "${wt}/specs/${feature}/.validated" ]]; then - attempts_file=".harness/validate-attempts-${feature}" + attempts_file="$STATE_DIR/validate-attempts-${feature}" attempts=$(cat "${attempts_file}" 2>/dev/null || echo 0) if (( attempts >= VALIDATE_CAP )); then echo "STUCK: ${feature} at /spec-validate (${VALIDATE_CAP}x)." >&2 @@ -298,17 +319,17 @@ for feature in ${in_flight[@]+"${in_flight[@]}"}; do && touch "specs/${feature}/.prd-passed" \ && git add "specs/${feature}/.prd-passed" \ && git commit -m "harness: PRD runner green for ${feature}" --quiet \ - && git push --quiet ) || true + && git push --quiet ) && TRANSITIONS=$(( TRANSITIONS + 1 )) || true else # Bounded retry: if the PRD runner keeps failing, the *plan* may be broken, # not just the code, and re-invoking implement forever burns compute. (Inv 8) - attempts_file=".harness/implement-attempts-${feature}" + attempts_file="$STATE_DIR/implement-attempts-${feature}" attempts=$(cat "${attempts_file}" 2>/dev/null || echo 0) if (( attempts >= IMPLEMENT_CAP )); then # Capture the latest failing output for the human's diagnosis dossier. - ( cd "${wt}" && ./prds/${feature}/run-prd-test.sh ) > ".harness/stuck-output-${feature}.log" 2>&1 || true + ( cd "${wt}" && ./prds/${feature}/run-prd-test.sh ) > "$STATE_DIR/stuck-output-${feature}.log" 2>&1 || true echo "STUCK: ${feature} at /implement-mainspec — PRD runner ${IMPLEMENT_CAP}x." >&2 - signal_stuck "$feature" "implement-mainspec" "$IMPLEMENT_CAP" ".harness/stuck-output-${feature}.log" + signal_stuck "$feature" "implement-mainspec" "$IMPLEMENT_CAP" "$STATE_DIR/stuck-output-${feature}.log" else echo $((attempts + 1)) > "${attempts_file}" run_claude implement-mainspec "$feature" $((attempts + 1)) "$wt" "/implement-mainspec ${feature}" @@ -319,18 +340,19 @@ for feature in ${in_flight[@]+"${in_flight[@]}"}; do && ! ( cd "${wt}" && ./scripts/local-checks.sh ); then # Optional gate. Auto-fix first (attempt 0), focused LLM fix (attempt 1), # then STUCK at LOCAL_CHECKS_CAP. (Inv 8) - attempts_file=".harness/local-check-attempts-${feature}" + attempts_file="$STATE_DIR/local-check-attempts-${feature}" attempts=$(cat "${attempts_file}" 2>/dev/null || echo 0) if (( attempts >= LOCAL_CHECKS_CAP )); then - ( cd "${wt}" && ./scripts/local-checks.sh ) > ".harness/stuck-output-${feature}.log" 2>&1 || true + ( cd "${wt}" && ./scripts/local-checks.sh ) > "$STATE_DIR/stuck-output-${feature}.log" 2>&1 || true echo "STUCK: ${feature} at local-checks (${LOCAL_CHECKS_CAP}x)." >&2 - signal_stuck "$feature" "local-checks" "$LOCAL_CHECKS_CAP" ".harness/stuck-output-${feature}.log" + signal_stuck "$feature" "local-checks" "$LOCAL_CHECKS_CAP" "$STATE_DIR/stuck-output-${feature}.log" elif (( attempts == 0 )); then ( cd "${wt}" && ./scripts/local-checks.sh fix || true ) if ! ( cd "${wt}" && git diff --quiet ); then ( cd "${wt}" \ && git commit -am "chore: auto-fix lint/format" --quiet \ && git push --quiet ) + TRANSITIONS=$(( TRANSITIONS + 1 )) fi echo 1 > "${attempts_file}" else @@ -338,30 +360,31 @@ for feature in ${in_flight[@]+"${in_flight[@]}"}; do echo $((attempts + 1)) > "${attempts_file}" fi - elif ! gh pr view "${branch}" >/dev/null 2>&1; then - gh pr create --base main --head "${branch}" --fill - rm -f ".harness/planning-attempts-${feature}" - rm -f ".harness/validate-attempts-${feature}" - rm -f ".harness/local-check-attempts-${feature}" - rm -f ".harness/implement-attempts-${feature}" + elif ! ghe pr view "${branch}" >/dev/null 2>&1; then + ghe pr create --base main --head "${branch}" --fill + TRANSITIONS=$(( TRANSITIONS + 1 )) + rm -f "$STATE_DIR/planning-attempts-${feature}" + rm -f "$STATE_DIR/validate-attempts-${feature}" + rm -f "$STATE_DIR/local-check-attempts-${feature}" + rm -f "$STATE_DIR/implement-attempts-${feature}" # No reviewer configured (empty marker) → nothing to converge on; hand # straight to the human for /evaluate-pr. Guard halts next tick. - [[ -z "$REVIEW_CLEAN_MARKER" ]] && touch ".harness/human-review-${feature}" + [[ -z "$REVIEW_CLEAN_MARKER" ]] && touch "$STATE_DIR/human-review-${feature}" # CONVERGED — the reviewer posted the clean marker. Hand the PR to the human # for /evaluate-pr. The guard above halts the feature next tick. # Checked BEFORE the findings loop so a clean PR never marches to a false STUCK # on a sticky historical COMMENTED review. elif reviewer_converged "${branch}"; then - touch ".harness/human-review-${feature}" + touch "$STATE_DIR/human-review-${feature}" # Reviewer has findings and hasn't signalled done. Address them if budget # remains; at FEEDBACK_CAP rounds without convergence, STUCK (covers genuine # non-convergence AND a reviewer that flubbed the marker — human takes over). - elif gh pr view "${branch}" --json reviews \ + elif ghe pr view "${branch}" --json reviews \ --jq '.reviews[] | select(.state=="CHANGES_REQUESTED" or .state=="COMMENTED")' \ 2>/dev/null | grep -q .; then - rounds_file=".harness/feedback-rounds-${feature}" + rounds_file="$STATE_DIR/feedback-rounds-${feature}" rounds=$(cat "${rounds_file}" 2>/dev/null || echo 0) if (( rounds >= FEEDBACK_CAP )); then echo "STUCK: ${feature} at PR review (${FEEDBACK_CAP} rounds)." >&2 @@ -376,34 +399,45 @@ done # 4. Cleanup pass: tear down per-feature worktree + counter files for # closed/merged PRs. Each finished feature is torn down independently. -for feature in $(git for-each-ref --format='%(refname:lstrip=4)' \ +for feature in $(git -C "$ENV_PATH" for-each-ref --format='%(refname:lstrip=4)' \ refs/remotes/origin/feature/ 2>/dev/null || true); do - state=$(gh pr view "feature/${feature}" --json state --jq .state 2>/dev/null || echo "") + state=$(ghe pr view "feature/${feature}" --json state --jq .state 2>/dev/null || echo "") if [[ "${state}" == "MERGED" || "${state}" == "CLOSED" ]]; then - git worktree remove "$(worktree_for "$feature")" --force 2>/dev/null || true - rm -f ".harness/feedback-rounds-${feature}" - rm -f ".harness/local-check-attempts-${feature}" - rm -f ".harness/implement-attempts-${feature}" - rm -f ".harness/planning-attempts-${feature}" - rm -f ".harness/validate-attempts-${feature}" - rm -f ".harness/stuck-${feature}" - rm -f ".harness/stuck-output-${feature}.log" - rm -f ".harness/stuck-body-${feature}.md" - rm -f ".harness/human-review-${feature}" - rm -f ".harness/human-review-posted-${feature}" - rm -f ".harness/human-review-body-${feature}.md" - rm -f ".harness/sessions-${feature}.tsv" + git -C "$ENV_PATH" worktree remove "$(worktree_for "$feature")" --force 2>/dev/null || true + # The worktree add created a local feature/ branch in the developer's + # clone; drop it so a reused feature name can't collide with a stale branch. + git -C "$ENV_PATH" branch -D "feature/${feature}" 2>/dev/null || true + rm -f "$STATE_DIR/feedback-rounds-${feature}" + rm -f "$STATE_DIR/local-check-attempts-${feature}" + rm -f "$STATE_DIR/implement-attempts-${feature}" + rm -f "$STATE_DIR/planning-attempts-${feature}" + rm -f "$STATE_DIR/validate-attempts-${feature}" + rm -f "$STATE_DIR/stuck-${feature}" + rm -f "$STATE_DIR/stuck-output-${feature}.log" + rm -f "$STATE_DIR/stuck-body-${feature}.md" + rm -f "$STATE_DIR/human-review-${feature}" + rm -f "$STATE_DIR/human-review-posted-${feature}" + rm -f "$STATE_DIR/human-review-body-${feature}.md" + rm -f "$STATE_DIR/sessions-${feature}.tsv" fi done # Post-merge memory update is NOT here. /learn runs in its own loop -# (scripts/learn-tick.sh, driven by a separate `/loop … /learn-loop`), in its own -# dedicated worktree, so a multi-minute memory rebuild never blocks — and is never -# blocked by — this feature/build loop. The two loops coordinate only through git -# (the refs/harness/last-learned watermark + ls-remote idempotency on learn/). -# See references/dispatcher-explained.md ("The memory loop"). +# (scripts/learn-dispatch.sh, driven by the CLI supervisor on its own interval), +# in its own dedicated worktree, so a multi-minute memory rebuild never blocks — +# and is never blocked by — this feature/build loop. The two loops coordinate only +# through git (the refs/harness/last-learned watermark + ls-remote idempotency on +# learn/). See references/dispatcher-explained.md ("The memory loop"). # STUCK escalation is handled inline in step 3 by signal_stuck (which opens or # comments on the PR with the session log + checklist). The human takes over # from there — diagnoses the context defect first, corrects it on the branch, # fixes the code, then merges. /learn picks up the context correction at merge. + +# Exit contract for the supervisor: 10 = advanced (re-invoke immediately to +# drain), 0 = idle (sleep the full interval). STUCK-only ticks made no +# transition, so they exit 0 — a stuck environment never hot-loops. +if (( TRANSITIONS > 0 )); then + exit 10 +fi +exit 0 diff --git a/skills/harness/harness-init/assets/harness-tick.sh b/skills/harness/harness-init/assets/harness-tick.sh deleted file mode 100755 index 2d487d4..0000000 --- a/skills/harness/harness-init/assets/harness-tick.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash -# harness-tick.sh — one outer-loop tick: sync the HOST worktree to main, then dispatch. -# -# This is the target the build loop (/loop, cron, …) invokes — NOT the dispatcher -# directly. It exists to keep the harness's own operating context current. -# -# WHY A WRAPPER. The dispatcher, scripts/bootstrap-worktree.sh, and .harness/env all -# live in the HOST worktree (../-harness) and are read FROM it as the loop runs. -# The host worktree sits at a detached HEAD and does NOT auto-advance when main moves, -# so without a sync step those would freeze at whatever commit the worktree was created -# on. Feature PIPELINE skills are unaffected — they run inside per-feature worktrees -# that branch from the PRD branch (off main), so new features pick up skill updates on -# their own. Only this loop-level infrastructure needs syncing; that's what this -# wrapper does. (The /learn skill + memory used to need this sync too, back when /learn -# ran in the host worktree; it now runs in its own dedicated worktree under its own -# loop — scripts/learn-tick.sh — which syncs itself, so the host worktree is purely the -# build loop's.) -# -# WHY HERE AND NOT IN THE DISPATCHER. The dispatcher must stay HEAD-agnostic: if it -# reset its own checkout mid-run it would overwrite the very file it's executing -# (and its flock is on $0). Doing the sync HERE, before exec, means the dispatcher -# always loads its freshest version cleanly. This wrapper is tiny and stable; on the -# rare occasion it changes on main, that change simply takes effect the next tick. - -set -euo pipefail -cd "$(dirname "${BASH_SOURCE[0]}")/.." # repo root of the host worktree - -git fetch --quiet origin - -# Force a clean, current detached checkout of origin/main. `-f --detach` is -# idempotent and self-healing: it recovers no matter what state a crash left the -# worktree in. This is the host-worktree analogue of the dispatcher's per-feature -# wipe. The memory loop never touches this worktree's working tree (it works in -# ../-harness-learn), so there is nothing here to race. -git checkout --quiet -f --detach origin/main -git clean -qfd # -d not -x: keep node_modules & .harness/* runtime state - -exec ./scripts/poll-and-dispatch.sh "$@" diff --git a/skills/harness/harness-init/assets/learn-loop-SKILL.md b/skills/harness/harness-init/assets/learn-loop-SKILL.md deleted file mode 100644 index 1b6d986..0000000 --- a/skills/harness/harness-init/assets/learn-loop-SKILL.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -name: learn-loop -description: One tick of the harness MEMORY loop. Checks whether main advanced since the last memory update and, if so, runs /learn in a dedicated worktree to open a learn/ PR. Run on an interval via /loop, alongside the build loop. ---- - -# learn-loop - -Run `./scripts/learn-tick.sh` from the harness host worktree root and report what it did. - -That is the entire skill. The intelligence is in the script — this exists only so -`/loop` has a slash-command-shaped target. Do not do any memory work in this session; -the script shells out to a fresh `claude -p "/learn …"` subprocess for the real work, -in its own `../-harness-learn` worktree, which is what keeps this outer session's -context from bloating across ticks. - -`learn-tick.sh` is the memory-loop counterpart of `harness-tick.sh`. It self-serializes -with its own `flock` (independent of the build loop), syncs a dedicated, reused learn -worktree to a clean `origin/main`, and — unless a `learn/` PR is already open -(it pauses while one awaits your review) — computes the range from the -`refs/harness/last-learned` watermark to current main and runs `/learn` over it. It -never touches the build loop's host worktree, so the two loops run fully in parallel. - -Start it alongside the build loop, from the same harness host worktree: - -``` -/loop 10m /learn-loop -``` diff --git a/skills/harness/harness-init/assets/poll-and-dispatch-SKILL.md b/skills/harness/harness-init/assets/poll-and-dispatch-SKILL.md deleted file mode 100644 index f662ac3..0000000 --- a/skills/harness/harness-init/assets/poll-and-dispatch-SKILL.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -name: poll-and-dispatch -description: One tick of the harness outer loop. Syncs the host worktree to main, then dispatches one skill per branch. Run on an interval via /loop. ---- - -# poll-and-dispatch - -Run `./scripts/harness-tick.sh` from the harness host worktree root and report what it did. - -That is the entire skill. The intelligence is in the scripts — this exists only -so `/loop` has a slash-command-shaped target. Do not do any feature work in this -session; the scripts shell out to fresh `claude -p` subprocesses for all real -work, which is what keeps this outer session's context from bloating across ticks. - -`harness-tick.sh` first force-syncs this host worktree to a clean `origin/main` -(so the dispatcher, its shared `harness-lib.sh`, and `.harness/env` are always -current), then `exec`s `./scripts/poll-and-dispatch.sh` — the deterministic, -HEAD-agnostic dispatcher. Never point `/loop` at the dispatcher directly, or -loop-infrastructure updates merged to main won't reach the loop. - -This is the **build loop** (features). The post-merge memory update (`/learn`) runs -in a separate loop — `/loop … /learn-loop` (`scripts/learn-tick.sh`) — so the two -never block each other. Start it in its own session alongside this one. From 5c9f65ce19f0249ae04e2f52103de3895a4bc7fe Mon Sep 17 00:00:00 2001 From: Rico Date: Sun, 5 Jul 2026 13:06:01 -0500 Subject: [PATCH 07/14] Add context-specs CLI core: registry, skill symlinking, add/remove/link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Zero-dependency Node CLI (node >=18) at bin/context-specs. 'add ' registers an environment in the gitignored environments.toml, symlinks every canonical skill into /.claude/skills/ (Claude Code follows skill-dir symlinks) plus the subagents, and writes a marker-delimited managed block to the env's .gitignore. 'link ' is the idempotent re-link used by bootstrap-worktree.sh for fresh worktrees. Eject-by-shadowing: a real committed directory with a skill's name is treated as the project's fork and left alone. /intent is deliberately NOT symlinked — /env-init installs it as a committed, project-owned copy. Co-Authored-By: Claude Fable 5 --- bin/context-specs | 66 ++++++++++++++++++++++++++ lib/add.js | 56 ++++++++++++++++++++++ lib/link.js | 115 ++++++++++++++++++++++++++++++++++++++++++++++ lib/paths.js | 20 ++++++++ lib/registry.js | 75 ++++++++++++++++++++++++++++++ lib/remove.js | 28 +++++++++++ lib/util.js | 42 +++++++++++++++++ package.json | 16 +++++++ 8 files changed, 418 insertions(+) create mode 100755 bin/context-specs create mode 100644 lib/add.js create mode 100644 lib/link.js create mode 100644 lib/paths.js create mode 100644 lib/registry.js create mode 100644 lib/remove.js create mode 100644 lib/util.js create mode 100644 package.json diff --git a/bin/context-specs b/bin/context-specs new file mode 100755 index 0000000..c0b5ee1 --- /dev/null +++ b/bin/context-specs @@ -0,0 +1,66 @@ +#!/usr/bin/env node +'use strict'; +// context-specs — the deterministic half of the harness. +// +// Tier 1 (harness repo) owned. Everything here is plain code: registering +// environments, symlinking the canonical skills into them, and supervising the +// dispatcher loops. The probabilistic half (project-specific setup) lives in +// the /env-init skill, which this CLI hands off to after `add`. + +const HELP = `context-specs — set up and run the coding harness across your environments + +Usage: context-specs [args] + +Setup + init [name] Create (or adopt) a harness repo from the context-specs template + add [--name n] Register an environment repo: symlink skills, write .gitignore + entries, add it to environments.toml. Then run /env-init inside it. + remove Unregister an environment (leaves its files and state in place) + link (Re-)create the skill/agent symlinks in a repo or worktree. + Idempotent; called automatically by bootstrap-worktree.sh. + +Run + start [name|--all] Start the background supervisor (build loop + memory loop) + stop [name|--all] Stop the supervisor + run [name] [--learn] One foreground tick, drained to idle. No daemon. + status [--fetch] One-shot table: every environment's features and phases + logs [-f] [--learn|--supervisor] Show (or follow) an environment's logs + doctor Check the harness, the registry, and every environment + +The dispatcher itself is deterministic bash (scripts/poll-and-dispatch.sh); +this CLI only schedules it. Exit 10 from a tick means "work advanced" and the +supervisor re-invokes immediately until the environment is idle (exit 0). +`; + +const commands = { + init: () => require('../lib/init'), + add: () => require('../lib/add'), + remove: () => require('../lib/remove'), + link: () => require('../lib/link').cli, + start: () => require('../lib/supervisor').start, + stop: () => require('../lib/supervisor').stop, + run: () => require('../lib/supervisor').runOnce, + __supervise: () => require('../lib/supervisor').supervise, + status: () => require('../lib/status'), + logs: () => require('../lib/logs'), + doctor: () => require('../lib/doctor'), +}; + +async function main() { + const [cmd, ...args] = process.argv.slice(2); + if (!cmd || cmd === '--help' || cmd === '-h' || cmd === 'help') { + process.stdout.write(HELP); + process.exit(cmd ? 0 : 1); + } + const load = commands[cmd]; + if (!load) { + console.error(`context-specs: unknown command '${cmd}'. Run 'context-specs --help'.`); + process.exit(1); + } + await load()(args); +} + +main().catch((err) => { + console.error(`context-specs: ${err.message}`); + process.exit(1); +}); diff --git a/lib/add.js b/lib/add.js new file mode 100644 index 0000000..00cf15f --- /dev/null +++ b/lib/add.js @@ -0,0 +1,56 @@ +'use strict'; +// `context-specs add ` — the deterministic half of environment setup. +// Registers the repo, symlinks the canonical skills/agents into it, and writes +// the managed .gitignore block. The probabilistic half — AGENTS.md, +// bootstrap-worktree.sh, local-checks, the Expert skeleton, a project-owned +// /intent — is /env-init's job, run by the developer in a Claude session +// inside the environment afterward. + +const fs = require('fs'); +const path = require('path'); +const registry = require('./registry'); +const { linkEnv, ensureGitignore } = require('./link'); +const { logsDir } = require('./paths'); +const { git } = require('./util'); + +module.exports = async function add(args) { + const positional = args.filter((a) => !a.startsWith('--')); + const nameFlag = args.includes('--name') ? args[args.indexOf('--name') + 1] : null; + const target = positional[0]; + if (!target) throw new Error('usage: context-specs add [--name ]'); + + const envPath = path.resolve(target); + if (!fs.existsSync(envPath)) throw new Error(`no such directory: ${envPath}`); + if (git(envPath, ['rev-parse', '--git-dir']) === null) { + throw new Error(`${envPath} is not a git repository`); + } + if (git(envPath, ['remote', 'get-url', 'origin']) === null) { + console.warn('warn: no `origin` remote — the harness claims PRDs and opens PRs through origin; add one before starting the loops.'); + } + + const name = nameFlag || path.basename(envPath); + const envs = registry.load(); + const existing = envs.find((e) => e.name === name); + if (existing && existing.path !== envPath) { + throw new Error(`name '${name}' is already registered for ${existing.path} — pass --name to disambiguate`); + } + + const { linked, agents, ejected } = linkEnv(envPath); + ensureGitignore(envPath); + if (!existing) { + envs.push({ name, path: envPath, enabled: true }); + registry.save(envs); + } + fs.mkdirSync(logsDir(name), { recursive: true }); + + console.log(`Registered environment '${name}' → ${envPath}`); + console.log(` linked ${linked.length} skills + ${agents.length} agents (gitignored symlinks)`); + if (ejected.length) console.log(` ejected (project-owned): ${ejected.join(', ')}`); + console.log(''); + console.log('Next: the Software 3.0 half. In the environment, run the setup skill:'); + console.log(` cd ${envPath}`); + console.log(' claude'); + console.log(' /env-init'); + console.log(''); + console.log("Once its PR is merged: 'context-specs start' (or 'run' for one foreground pass)."); +}; diff --git a/lib/link.js b/lib/link.js new file mode 100644 index 0000000..eeb05f8 --- /dev/null +++ b/lib/link.js @@ -0,0 +1,115 @@ +'use strict'; +// The skill-delivery engine. Tier-1 skills reach an environment as SYMLINKS in +// its .claude/skills/ (gitignored — Claude Code follows skill-directory +// symlinks). Two callers: +// - `context-specs add ` at registration time, and +// - the deterministic header of the environment's bootstrap-worktree.sh for +// every fresh worktree (gitignored symlinks do not materialize in new git +// worktrees, so each one must be re-linked). +// Idempotent and fast by construction. +// +// Eject-by-shadowing: if the target already has a REAL directory (or file) of +// the same name, it is the project's own committed fork — skip it and report +// it as "ejected". Deleting the committed copy re-adopts the canonical skill on +// the next link. + +const fs = require('fs'); +const path = require('path'); +const { skillsDir, subagentsDir } = require('./paths'); + +// /intent is NOT symlinked: it is a Software 3.0 artifact — /env-init copies it +// into the environment (verbatim or customized) as a committed, project-owned +// skill. It is one of the two developer-owned levers (with the Expert). +const EXCLUDED_SKILLS = new Set(['intent']); + +// Enumerate canonical skills: skills///SKILL.md → flat . +function canonicalSkills() { + const out = []; + for (const group of fs.readdirSync(skillsDir)) { + const groupDir = path.join(skillsDir, group); + if (!fs.statSync(groupDir).isDirectory()) continue; + for (const name of fs.readdirSync(groupDir)) { + const dir = path.join(groupDir, name); + if (!EXCLUDED_SKILLS.has(name) && fs.existsSync(path.join(dir, 'SKILL.md'))) { + out.push({ name, dir }); + } + } + } + return out.sort((a, b) => a.name.localeCompare(b.name)); +} + +function canonicalAgents() { + if (!fs.existsSync(subagentsDir)) return []; + return fs.readdirSync(subagentsDir) + .filter((f) => f.endsWith('.md')) + .map((f) => ({ name: f, file: path.join(subagentsDir, f) })); +} + +// Create/refresh one symlink; returns 'linked' | 'ejected'. +function ensureLink(target, linkPath) { + let st = null; + try { st = fs.lstatSync(linkPath); } catch {} + if (st && !st.isSymbolicLink()) return 'ejected'; // real dir/file = project-owned fork + if (st) fs.unlinkSync(linkPath); // stale/moved symlink: heal it + fs.symlinkSync(target, linkPath); + return 'linked'; +} + +function linkEnv(envPath) { + const root = path.resolve(envPath); + if (!fs.existsSync(root)) throw new Error(`no such directory: ${root}`); + const skillsTarget = path.join(root, '.claude', 'skills'); + const agentsTarget = path.join(root, '.claude', 'agents'); + fs.mkdirSync(skillsTarget, { recursive: true }); + fs.mkdirSync(agentsTarget, { recursive: true }); + + const linked = []; + const ejected = []; + for (const { name, dir } of canonicalSkills()) { + const result = ensureLink(dir, path.join(skillsTarget, name)); + (result === 'linked' ? linked : ejected).push(name); + } + const agents = []; + for (const { name, file } of canonicalAgents()) { + const result = ensureLink(file, path.join(agentsTarget, name)); + (result === 'linked' ? agents : ejected).push(name); + } + return { linked, agents, ejected }; +} + +// The env-repo .gitignore entries for everything link creates. The block is +// marker-delimited so add can rewrite it idempotently. +const GITIGNORE_START = '# >>> context-specs (managed by `context-specs add` — do not edit inside markers) >>>'; +const GITIGNORE_END = '# <<< context-specs <<<'; + +function gitignoreBlock() { + const lines = [GITIGNORE_START]; + for (const { name } of canonicalSkills()) lines.push(`.claude/skills/${name}`); + for (const { name } of canonicalAgents()) lines.push(`.claude/agents/${name}`); + lines.push(GITIGNORE_END); + return lines.join('\n'); +} + +function ensureGitignore(envPath) { + const file = path.join(envPath, '.gitignore'); + const block = gitignoreBlock(); + let text = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : ''; + const start = text.indexOf(GITIGNORE_START); + const end = text.indexOf(GITIGNORE_END); + if (start !== -1 && end !== -1) { + text = text.slice(0, start) + block + text.slice(end + GITIGNORE_END.length); + } else { + text = text.replace(/\n*$/, text ? '\n\n' : '') + block + '\n'; + } + fs.writeFileSync(file, text); +} + +async function cli(args) { + const target = args[0]; + if (!target) throw new Error('usage: context-specs link '); + const { linked, agents, ejected } = linkEnv(target); + console.log(`linked ${linked.length} skills + ${agents.length} agents into ${path.resolve(target)}/.claude/`); + if (ejected.length) console.log(`ejected (project-owned, left alone): ${ejected.join(', ')}`); +} + +module.exports = { linkEnv, canonicalSkills, canonicalAgents, ensureGitignore, gitignoreBlock, cli, GITIGNORE_START, GITIGNORE_END }; diff --git a/lib/paths.js b/lib/paths.js new file mode 100644 index 0000000..4b04f3b --- /dev/null +++ b/lib/paths.js @@ -0,0 +1,20 @@ +'use strict'; +const path = require('path'); + +// The harness repo root. The CLI always lives at /bin + /lib, +// so its own location IS the harness location — no lookup, no env var needed. +const HOME = path.resolve(__dirname, '..'); + +module.exports = { + HOME, + scriptsDir: path.join(HOME, 'scripts'), + skillsDir: path.join(HOME, 'skills'), + subagentsDir: path.join(HOME, 'subagents'), + registryPath: path.join(HOME, 'environments.toml'), + registryExamplePath: path.join(HOME, 'environments.example.toml'), + stateRoot: path.join(HOME, 'state'), + stateDir: (name) => path.join(HOME, 'state', name), + logsDir: (name) => path.join(HOME, 'state', name, 'logs'), + pidFile: (name) => path.join(HOME, 'state', name, 'supervisor.pid'), + binPath: path.join(HOME, 'bin', 'context-specs'), +}; diff --git a/lib/registry.js b/lib/registry.js new file mode 100644 index 0000000..2e15df4 --- /dev/null +++ b/lib/registry.js @@ -0,0 +1,75 @@ +'use strict'; +// environments.toml — the per-machine registry of environments this harness +// operates on. Gitignored (paths differ per developer); written only by +// `add`/`remove`, never hand-edited in normal use. Deliberately a tiny TOML +// subset so the CLI stays zero-dependency: +// +// [[environment]] +// name = "myapp" +// path = "/abs/path/to/myapp" +// enabled = true + +const fs = require('fs'); +const { registryPath } = require('./paths'); + +function parse(text) { + const envs = []; + let cur = null; + for (const raw of text.split('\n')) { + const line = raw.trim(); + if (!line || line.startsWith('#')) continue; + if (line === '[[environment]]') { cur = { enabled: true }; envs.push(cur); continue; } + const m = line.match(/^(\w+)\s*=\s*(.+)$/); + if (!m || !cur) continue; + let [, key, value] = m; + value = value.trim(); + if (value === 'true') value = true; + else if (value === 'false') value = false; + else value = value.replace(/^"(.*)"$/, '$1'); + cur[key] = value; + } + return envs; +} + +function serialize(envs) { + const lines = ['# Environments registered with this harness (managed by `context-specs add`).', '']; + for (const e of envs) { + lines.push('[[environment]]'); + lines.push(`name = "${e.name}"`); + lines.push(`path = "${e.path}"`); + lines.push(`enabled = ${e.enabled !== false}`); + if (e.interval) lines.push(`interval = ${e.interval}`); + lines.push(''); + } + return lines.join('\n'); +} + +function load() { + if (!fs.existsSync(registryPath)) return []; + return parse(fs.readFileSync(registryPath, 'utf8')); +} + +function save(envs) { + fs.writeFileSync(registryPath, serialize(envs)); +} + +function find(name) { + return load().find((e) => e.name === name) || null; +} + +// Resolve [name] the run/start/stop/logs commands take: explicit name, or the +// sole registered environment, or an error listing the choices. +function resolveOne(name) { + const envs = load(); + if (name) { + const env = envs.find((e) => e.name === name); + if (!env) throw new Error(`no environment named '${name}' (registered: ${envs.map((e) => e.name).join(', ') || 'none'})`); + return env; + } + const enabled = envs.filter((e) => e.enabled !== false); + if (enabled.length === 1) return enabled[0]; + if (!enabled.length) throw new Error("no environments registered — run 'context-specs add ' first"); + throw new Error(`multiple environments registered — name one of: ${enabled.map((e) => e.name).join(', ')}`); +} + +module.exports = { load, save, find, resolveOne, parse, serialize }; diff --git a/lib/remove.js b/lib/remove.js new file mode 100644 index 0000000..8823996 --- /dev/null +++ b/lib/remove.js @@ -0,0 +1,28 @@ +'use strict'; +// Unregister an environment. Deliberately conservative: only the registry entry +// is removed. The environment's files (symlinks, .gitignore block, committed +// artifacts) and its state dir are left in place and printed for manual cleanup +// — deleting things in a repo we no longer manage is not this command's call. + +const fs = require('fs'); +const registry = require('./registry'); +const { stateDir, pidFile } = require('./paths'); +const { isPidAlive } = require('./util'); + +module.exports = async function remove(args) { + const name = args[0]; + if (!name) throw new Error('usage: context-specs remove '); + const envs = registry.load(); + const env = envs.find((e) => e.name === name); + if (!env) throw new Error(`no environment named '${name}'`); + + const pf = pidFile(name); + if (fs.existsSync(pf) && isPidAlive(parseInt(fs.readFileSync(pf, 'utf8'), 10))) { + throw new Error(`supervisor for '${name}' is running — 'context-specs stop ${name}' first`); + } + + registry.save(envs.filter((e) => e.name !== name)); + console.log(`Unregistered '${name}'. Left in place (delete manually if you want them gone):`); + console.log(` ${env.path}/.claude/ symlinks + the managed .gitignore block`); + console.log(` ${stateDir(name)} runtime state and logs`); +}; diff --git a/lib/util.js b/lib/util.js new file mode 100644 index 0000000..de8eb8b --- /dev/null +++ b/lib/util.js @@ -0,0 +1,42 @@ +'use strict'; +const { execFileSync } = require('child_process'); +const readline = require('readline'); + +// Run a command, return trimmed stdout, or null on any failure. The callers +// that need the distinction between "empty output" and "failed" test for null. +function tryRun(cmd, args, opts = {}) { + try { + return execFileSync(cmd, args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], ...opts }).trim(); + } catch { + return null; + } +} + +// git against a specific repo without changing cwd. +function git(repo, args) { + return tryRun('git', ['-C', repo, ...args]); +} + +function ask(question) { + const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); + return new Promise((resolve) => rl.question(question, (a) => { rl.close(); resolve(a.trim()); })); +} + +async function confirm(question) { + const a = await ask(`${question} [y/N] `); + return /^y(es)?$/i.test(a); +} + +// Render rows as a padded text table. rows = array of arrays; first row = header. +function renderTable(rows) { + if (!rows.length) return ''; + const widths = rows[0].map((_, i) => Math.max(...rows.map((r) => String(r[i] ?? '').length))); + const line = (r) => r.map((c, i) => String(c ?? '').padEnd(widths[i])).join(' ').trimEnd(); + return [line(rows[0]), widths.map((w) => '-'.repeat(w)).join(' '), ...rows.slice(1).map(line)].join('\n'); +} + +function isPidAlive(pid) { + try { process.kill(pid, 0); return true; } catch { return false; } +} + +module.exports = { tryRun, git, ask, confirm, renderTable, isPidAlive }; diff --git a/package.json b/package.json new file mode 100644 index 0000000..5a11228 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "context-specs", + "version": "0.1.0", + "description": "Harness engineering in practice: a deterministic CLI + dispatcher that drives probabilistic coding agents from PRD to a guaranteed output — a PR that is ready to merge or STUCK with a diagnosis.", + "license": "Apache-2.0", + "bin": { + "context-specs": "bin/context-specs" + }, + "engines": { + "node": ">=18" + }, + "repository": { + "type": "git", + "url": "https://github.com/capitalone/context-specs.git" + } +} From 6d6e67ca73002ad6cbe36ca16986c66e3528786b Mon Sep 17 00:00:00 2001 From: Rico Date: Sun, 5 Jul 2026 13:08:10 -0500 Subject: [PATCH 08/14] Add CLI runtime: supervisor (start/stop/run), status, logs, doctor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - supervisor: one detached process per environment, two independent loops. Build tick every INTERVAL (default 5m) with drain-on-10 — real work re-invokes immediately instead of waiting out the poll; errors back off exponentially (capped 1h). Learn tick every LEARN_INTERVAL (default 10m), never drains. 'run' is the foreground one-shot: drain to idle and exit, no daemon. - status: deterministic table derived from committed sentinels + state files — no gh calls, works offline, phases mirror the dispatcher's if/elif chain. - doctor: absorbs the old preflight.sh; adds the two-tier failure modes (broken/foreign symlinks, missing link header in bootstrap, leftover single-repo-era dispatcher artifacts in an environment). Co-Authored-By: Claude Fable 5 --- lib/doctor.js | 109 ++++++++++++++++++++++++++++++++++++ lib/logs.js | 20 +++++++ lib/status.js | 72 ++++++++++++++++++++++++ lib/supervisor.js | 138 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 339 insertions(+) create mode 100644 lib/doctor.js create mode 100644 lib/logs.js create mode 100644 lib/status.js create mode 100644 lib/supervisor.js diff --git a/lib/doctor.js b/lib/doctor.js new file mode 100644 index 0000000..1598993 --- /dev/null +++ b/lib/doctor.js @@ -0,0 +1,109 @@ +'use strict'; +// Health checks for the harness repo, the registry, and every registered +// environment. Absorbs the old harness-init preflight.sh, plus the failure +// modes the two-tier split introduces (broken symlinks after a move, leftover +// single-repo-era artifacts). Report-only: prints [ok]/[warn]/[MISS], never +// mutates. Exits 1 if any [MISS]. + +const fs = require('fs'); +const path = require('path'); +const registry = require('./registry'); +const { HOME, scriptsDir, stateRoot, registryPath } = require('./paths'); +const { tryRun, git } = require('./util'); +const { canonicalSkills, canonicalAgents, GITIGNORE_START } = require('./link'); + +let missed = false; +const ok = (m) => console.log(` [ok] ${m}`); +const warn = (m) => console.log(` [warn] ${m}`); +const miss = (m) => { console.log(` [MISS] ${m}`); missed = true; }; + +function checkHarness() { + console.log(`Harness repo: ${HOME}`); + const major = parseInt(process.versions.node.split('.')[0], 10); + major >= 18 ? ok(`node ${process.versions.node}`) : miss(`node >=18 required (found ${process.versions.node})`); + + for (const [cmd, why, fatal] of [ + ['bash', 'runs the dispatcher', true], + ['git', 'everything', true], + ['gh', 'PR creation, review polling, STUCK signals', true], + ['claude', "the dispatcher shells out to 'claude -p'", true], + ['flock', 'tick serialization (second line of defense behind the supervisor)', false], + ['uuidgen', 'session ids (falls back to /proc or a pseudo-id)', false], + ]) { + if (tryRun('sh', ['-c', `command -v ${cmd}`]) !== null) ok(`${cmd} on PATH`); + else (fatal ? miss : warn)(`${cmd} not on PATH — ${why}`); + } + if (tryRun('gh', ['auth', 'status']) !== null) ok('gh authenticated'); + else warn('gh not authenticated (gh auth login) — PR operations will fail'); + + for (const s of ['poll-and-dispatch.sh', 'learn-dispatch.sh']) { + const f = path.join(scriptsDir, s); + if (!fs.existsSync(f)) miss(`${s} missing from scripts/`); + else if (!(fs.statSync(f).mode & 0o100)) miss(`${s} not executable (chmod +x)`); + else ok(`scripts/${s} executable`); + } + fs.existsSync(path.join(scriptsDir, 'harness-lib.sh')) ? ok('scripts/harness-lib.sh present') : miss('scripts/harness-lib.sh missing'); + + try { fs.mkdirSync(stateRoot, { recursive: true }); fs.accessSync(stateRoot, fs.constants.W_OK); ok('state/ writable'); } + catch { miss('state/ not writable'); } + + if (!fs.existsSync(registryPath)) warn("no environments.toml yet — run 'context-specs add '"); + else { try { registry.load(); ok('environments.toml parses'); } catch (e) { miss(`environments.toml unreadable: ${e.message}`); } } +} + +function checkEnv(env) { + console.log(`\nEnvironment '${env.name}': ${env.path}`); + if (!fs.existsSync(env.path)) { miss('path does not exist'); return; } + if (git(env.path, ['rev-parse', '--git-dir']) === null) { miss('not a git repository'); return; } + git(env.path, ['remote', 'get-url', 'origin']) !== null ? ok('origin remote') : miss('no origin remote — the harness works entirely through origin'); + + // Tier-2 artifacts (created by /env-init). + fs.existsSync(path.join(env.path, '.harness', 'env')) ? ok('.harness/env config') : warn('.harness/env missing — run /env-init in this environment'); + fs.existsSync(path.join(env.path, 'AGENTS.md')) ? ok('AGENTS.md') : warn('AGENTS.md missing — run /env-init'); + const bootstrap = path.join(env.path, 'scripts', 'bootstrap-worktree.sh'); + if (!fs.existsSync(bootstrap)) warn('scripts/bootstrap-worktree.sh missing — fresh worktrees will not be provisioned or re-linked'); + else if (!fs.readFileSync(bootstrap, 'utf8').includes('context-specs')) warn('bootstrap-worktree.sh lacks the `context-specs link` header — fresh worktrees will miss the tier-1 skills'); + else ok('bootstrap-worktree.sh with link header'); + fs.existsSync(path.join(env.path, '.claude', 'skills', 'intent', 'SKILL.md')) ? ok('project-owned /intent') : warn('/intent not installed — run /env-init'); + fs.existsSync(path.join(env.path, '.claude', 'skills', 'expert', 'SKILL.md')) ? ok('Expert (long-term memory)') : warn('Expert skeleton not seeded — run /env-init'); + + // Symlink integrity for every canonical skill/agent. + let ejected = []; + for (const { name, dir } of canonicalSkills()) { + const lp = path.join(env.path, '.claude', 'skills', name); + let st = null; + try { st = fs.lstatSync(lp); } catch {} + if (!st) miss(`skill '${name}' not linked — run 'context-specs link ${env.path}'`); + else if (!st.isSymbolicLink()) ejected.push(name); + else if (fs.realpathSync(lp) !== fs.realpathSync(dir)) warn(`skill '${name}' links outside this harness (${fs.readlinkSync(lp)})`); + } + for (const { name, file } of canonicalAgents()) { + const lp = path.join(env.path, '.claude', 'agents', name); + let st = null; + try { st = fs.lstatSync(lp); } catch {} + if (!st) miss(`agent '${name}' not linked — run 'context-specs link ${env.path}'`); + else if (st.isSymbolicLink() && fs.realpathSync(lp) !== fs.realpathSync(file)) warn(`agent '${name}' links outside this harness`); + } + if (ejected.length) ok(`ejected (project-owned forks): ${ejected.join(', ')}`); + const gi = path.join(env.path, '.gitignore'); + fs.existsSync(gi) && fs.readFileSync(gi, 'utf8').includes(GITIGNORE_START) + ? ok('managed .gitignore block') + : warn("managed .gitignore block missing — re-run 'context-specs add'"); + + // Leftovers from the single-repo era (pre-two-tier installs). + const legacy = ['scripts/poll-and-dispatch.sh', 'scripts/harness-tick.sh', 'scripts/harness-lib.sh', 'scripts/learn-tick.sh', + '.claude/skills/poll-and-dispatch', '.claude/skills/learn-loop'] + .filter((f) => fs.existsSync(path.join(env.path, f))); + if (legacy.length) { + warn(`legacy single-repo harness artifacts found (two dispatchers would confuse, though claims stay atomic): ${legacy.join(', ')}`); + warn(' remove them in the environment: git rm ' + legacy.join(' ')); + } +} + +module.exports = async function doctor() { + checkHarness(); + for (const env of registry.load()) checkEnv(env); + console.log(''); + if (missed) { console.log('doctor: problems found (see [MISS] above)'); process.exit(1); } + console.log('doctor: healthy'); +}; diff --git a/lib/logs.js b/lib/logs.js new file mode 100644 index 0000000..313f59b --- /dev/null +++ b/lib/logs.js @@ -0,0 +1,20 @@ +'use strict'; +const fs = require('fs'); +const path = require('path'); +const { spawn } = require('child_process'); +const registry = require('./registry'); +const { logsDir } = require('./paths'); + +module.exports = async function logs(args) { + const follow = args.includes('-f') || args.includes('--follow'); + const which = args.includes('--learn') ? 'learn.log' + : args.includes('--supervisor') ? 'supervisor.log' : 'build.log'; + const env = registry.resolveOne(args.find((a) => !a.startsWith('-'))); + const file = path.join(logsDir(env.name), which); + if (!fs.existsSync(file)) { console.log(`no ${which} yet for '${env.name}' (${file})`); return; } + if (follow) { + spawn('tail', ['-n', '50', '-f', file], { stdio: 'inherit' }); + return new Promise(() => {}); // tail owns the terminal until Ctrl-C + } + process.stdout.write(fs.readFileSync(file, 'utf8')); +}; diff --git a/lib/status.js b/lib/status.js new file mode 100644 index 0000000..57b4f45 --- /dev/null +++ b/lib/status.js @@ -0,0 +1,72 @@ +'use strict'; +// One-shot, deterministic render of the whole harness's state. Everything is +// derived from artifacts — committed sentinels on the feature branches, counter +// and sentinel files in state//, the pidfile — exactly the "state lives on +// disk + branches" invariant, read instead of written. No gh calls: fast and +// offline; PR-level state is one click away on GitHub. Remote-tracking refs are +// as of the last fetch (a tick fetches every interval); pass --fetch to update +// them first. + +const fs = require('fs'); +const path = require('path'); +const registry = require('./registry'); +const { stateDir, pidFile } = require('./paths'); +const { git, renderTable, isPidAlive } = require('./util'); + +// Phase from committed sentinels, mirroring the dispatcher's if/elif chain. +function phaseFor(envPath, feature) { + const has = (f) => git(envPath, ['cat-file', '-e', `origin/feature/${feature}:specs/${feature}/${f}`]) !== null; + if (!has('.planning-done')) return 'spec-planning'; + if (!has('.validated')) return 'spec-validate'; + if (!has('.prd-passed')) return 'implement'; + return 'checks/PR'; +} + +function counterFor(name, feature, phase) { + const files = { + 'spec-planning': `planning-attempts-${feature}`, + 'spec-validate': `validate-attempts-${feature}`, + implement: `implement-attempts-${feature}`, + 'checks/PR': `feedback-rounds-${feature}`, + }; + const alt = phase === 'checks/PR' ? `local-check-attempts-${feature}` : null; + let n = 0; + for (const f of [files[phase], alt].filter(Boolean)) { + try { n = Math.max(n, parseInt(fs.readFileSync(path.join(stateDir(name), f), 'utf8'), 10) || 0); } catch {} + } + return n || ''; +} + +module.exports = async function status(args) { + const envs = registry.load(); + if (!envs.length) { console.log("no environments registered — 'context-specs add '"); return; } + + const rows = [['env', 'feature', 'phase', 'attempts', 'flag', 'supervisor']]; + for (const env of envs) { + if (args.includes('--fetch')) git(env.path, ['fetch', '--quiet', 'origin']); + let sup = 'stopped'; + try { + const pid = parseInt(fs.readFileSync(pidFile(env.name), 'utf8'), 10); + if (isPidAlive(pid)) sup = `running (${pid})`; + } catch {} + if (env.enabled === false) sup = 'disabled'; + + const refs = git(env.path, ['for-each-ref', '--format=%(refname:lstrip=4)', 'refs/remotes/origin/feature/']) || ''; + const features = refs.split('\n').filter(Boolean) + .filter((f) => git(env.path, ['cat-file', '-e', `origin/feature/${f}:prds/${f}/prd.md`]) !== null); + + if (!features.length) { + rows.push([env.name, '—', 'idle', '', '', sup]); + continue; + } + for (const f of features) { + const sd = stateDir(env.name); + const flag = fs.existsSync(path.join(sd, `stuck-${f}`)) ? 'STUCK' + : fs.existsSync(path.join(sd, `human-review-${f}`)) ? 'HUMAN_REVIEW' : ''; + const phase = phaseFor(env.path, f); + rows.push([env.name, f, phase, counterFor(env.name, f, phase), flag, sup]); + } + } + console.log(renderTable(rows)); + if (!args.includes('--fetch')) console.log('\n(branch state as of each environment’s last fetch — pass --fetch to refresh)'); +}; diff --git a/lib/supervisor.js b/lib/supervisor.js new file mode 100644 index 0000000..68c17b7 --- /dev/null +++ b/lib/supervisor.js @@ -0,0 +1,138 @@ +'use strict'; +// The scheduler around the deterministic dispatcher. One detached supervisor +// process per environment, each running two independent loops: +// +// build loop — scripts/poll-and-dispatch.sh every INTERVAL (default 5m). +// Exit 10 ("advanced") → re-invoke IMMEDIATELY: real work drains +// at machine speed instead of waiting out the poll interval. +// Exit 0 ("idle") → sleep the interval. Anything else → error; +// exponential backoff, capped at 1h. +// learn loop — scripts/learn-dispatch.sh every LEARN_INTERVAL (default 10m). +// Never drains: after a run, the open learn/ PR pauses it. +// +// The supervisor contains no decisions about WHAT to run — the dispatcher's +// exit code is the entire protocol. Intervals come from env vars INTERVAL / +// LEARN_INTERVAL (seconds) or a per-env `interval` in environments.toml. + +const fs = require('fs'); +const path = require('path'); +const { spawn, spawnSync } = require('child_process'); +const registry = require('./registry'); +const { scriptsDir, logsDir, pidFile, binPath } = require('./paths'); +const { isPidAlive } = require('./util'); + +const BUILD_SCRIPT = path.join(scriptsDir, 'poll-and-dispatch.sh'); +const LEARN_SCRIPT = path.join(scriptsDir, 'learn-dispatch.sh'); +const BACKOFF_CAP_S = 3600; + +function targets(args) { + if (args.includes('--all')) { + const envs = registry.load().filter((e) => e.enabled !== false); + if (!envs.length) throw new Error('no environments registered'); + return envs; + } + return [registry.resolveOne(args.find((a) => !a.startsWith('--')))]; +} + +function readPid(name) { + try { return parseInt(fs.readFileSync(pidFile(name), 'utf8'), 10); } catch { return null; } +} + +async function start(args) { + for (const env of targets(args)) { + const pid = readPid(env.name); + if (pid && isPidAlive(pid)) { + console.log(`${env.name}: supervisor already running (pid ${pid})`); + continue; + } + fs.mkdirSync(logsDir(env.name), { recursive: true }); + const out = fs.openSync(path.join(logsDir(env.name), 'supervisor.log'), 'a'); + const child = spawn(process.execPath, [binPath, '__supervise', env.name], { + detached: true, + stdio: ['ignore', out, out], + }); + child.unref(); + fs.writeFileSync(pidFile(env.name), String(child.pid)); + console.log(`${env.name}: supervisor started (pid ${child.pid}) — logs: context-specs logs ${env.name} -f`); + } +} + +async function stop(args) { + for (const env of targets(args)) { + const pid = readPid(env.name); + if (!pid || !isPidAlive(pid)) { + console.log(`${env.name}: not running`); + try { fs.unlinkSync(pidFile(env.name)); } catch {} + continue; + } + process.kill(pid, 'SIGTERM'); + const deadline = Date.now() + 10_000; + while (isPidAlive(pid) && Date.now() < deadline) await sleep(200); + if (isPidAlive(pid)) process.kill(pid, 'SIGKILL'); + try { fs.unlinkSync(pidFile(env.name)); } catch {} + console.log(`${env.name}: stopped`); + } +} + +// `run` — one FOREGROUND pass, drained to idle, then exit. No daemon: keeps +// re-invoking the tick while it reports "advanced" (10), stops at idle (0), +// propagates errors. The interactive way to watch the harness work. +async function runOnce(args) { + const learn = args.includes('--learn'); + const env = registry.resolveOne(args.find((a) => !a.startsWith('--'))); + const script = learn ? LEARN_SCRIPT : BUILD_SCRIPT; + for (;;) { + const { status } = spawnSync('bash', [script, env.path, env.name], { stdio: 'inherit' }); + if (status === 10) continue; // advanced — drain + process.exit(status ?? 1); + } +} + +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); + +function tick(script, env, logFile) { + return new Promise((resolve) => { + const out = fs.openSync(logFile, 'a'); + fs.writeSync(out, `\n--- ${new Date().toISOString()} tick ---\n`); + const child = spawn('bash', [script, env.path, env.name], { stdio: ['ignore', out, out] }); + child.on('exit', (code) => { fs.closeSync(out); resolve(code ?? 1); }); + child.on('error', () => { fs.closeSync(out); resolve(1); }); + }); +} + +// Hidden command the detached child runs. Two setTimeout-chain loops; SIGTERM +// exits cleanly (in-flight bash tick is left to finish its own flock-guarded +// work — the next supervisor simply takes over the schedule). +async function supervise(args) { + const env = registry.resolveOne(args[0]); + const interval = (parseInt(process.env.INTERVAL, 10) || parseInt(env.interval, 10) || 300) * 1000; + const learnInterval = (parseInt(process.env.LEARN_INTERVAL, 10) || 600) * 1000; + const logs = logsDir(env.name); + fs.mkdirSync(logs, { recursive: true }); + console.log(`[supervisor] ${env.name}: build every ${interval / 1000}s (drain on advance), learn every ${learnInterval / 1000}s`); + + let running = true; + process.on('SIGTERM', () => { running = false; process.exit(0); }); + process.on('SIGINT', () => { running = false; process.exit(0); }); + + const loop = async (script, logName, base, drain) => { + let backoff = base; + while (running) { + const code = await tick(script, env, path.join(logs, logName)); + if (code === 10 && drain) { backoff = base; continue; } + if (code === 0) backoff = base; + else { + backoff = Math.min(backoff * 2, BACKOFF_CAP_S * 1000); + console.log(`[supervisor] ${env.name}: ${logName} tick exited ${code}; backing off ${backoff / 1000}s`); + } + await sleep(backoff); + } + }; + + await Promise.all([ + loop(BUILD_SCRIPT, 'build.log', interval, true), + loop(LEARN_SCRIPT, 'learn.log', learnInterval, false), + ]); +} + +module.exports = { start, stop, runOnce, supervise }; From 196a868aa7111a3c4e9c48a00cf55365f37f06a2 Mon Sep 17 00:00:00 2001 From: Rico Date: Sun, 5 Jul 2026 13:09:05 -0500 Subject: [PATCH 09/14] Add init command: create or adopt a harness repo from the template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'init ' clones the template, renames origin→upstream (updates come from upstream; origin stays free for the user's own remote), seeds the gitignored environments.toml from the committed example, creates state/, and offers gh repo create. 'init' with no args adopts the current clone. Co-Authored-By: Claude Fable 5 --- .gitignore | 5 +++ environments.example.toml | 10 ++++++ lib/init.js | 66 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 environments.example.toml create mode 100644 lib/init.js diff --git a/.gitignore b/.gitignore index fdedff0..9bfdfcd 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,8 @@ __pycache__/ # Harness worktrees (per implement-mainspec parallel mode) .claude/worktrees/ + +# Per-machine harness runtime (managed by the context-specs CLI) +/state/ +/environments.toml +node_modules/ diff --git a/environments.example.toml b/environments.example.toml new file mode 100644 index 0000000..f8fb3a3 --- /dev/null +++ b/environments.example.toml @@ -0,0 +1,10 @@ +# environments.toml — the per-machine registry of environments this harness +# operates on. Your real environments.toml is GITIGNORED (paths differ per +# developer); this example documents the shape. You never edit it by hand: +# `context-specs add ` and `context-specs remove ` manage it. +# +# [[environment]] +# name = "myapp" # unique; defaults to the directory basename +# path = "/home/you/code/myapp" # absolute path to your clone +# enabled = true # false = skipped by start --all and status +# interval = 300 # optional per-env build-tick interval (seconds) diff --git a/lib/init.js b/lib/init.js new file mode 100644 index 0000000..50323d8 --- /dev/null +++ b/lib/init.js @@ -0,0 +1,66 @@ +'use strict'; +// `context-specs init [name]` — create (or adopt) a HARNESS repo. +// +// The context-specs repo doubles as the template: init clones it, renames +// origin → upstream (so `git pull upstream main` is the update path and origin +// stays free for the user's own remote), and prepares the per-machine pieces +// (registry, state/). Run with no args inside an existing clone, it "adopts" +// that clone as a harness instead. + +const fs = require('fs'); +const path = require('path'); +const { execFileSync } = require('child_process'); +const { HOME, registryPath, registryExamplePath } = require('./paths'); +const { tryRun, git, confirm } = require('./util'); + +const TEMPLATE_URL = process.env.CONTEXT_SPECS_TEMPLATE || 'https://github.com/capitalone/context-specs.git'; + +async function adopt(root) { + // Point `upstream` at the template so `context-specs`/git updates have a home. + const remotes = (git(root, ['remote']) || '').split('\n').filter(Boolean); + if (!remotes.includes('upstream')) { + const originUrl = git(root, ['remote', 'get-url', 'origin']); + if (originUrl && originUrl.replace(/\.git$/, '') === TEMPLATE_URL.replace(/\.git$/, '')) { + git(root, ['remote', 'rename', 'origin', 'upstream']); + console.log('renamed origin → upstream (the template; your own remote can take origin)'); + } else { + git(root, ['remote', 'add', 'upstream', TEMPLATE_URL]); + console.log(`added upstream → ${TEMPLATE_URL}`); + } + } + if (!fs.existsSync(path.join(root, 'environments.toml'))) { + const example = path.join(root, 'environments.example.toml'); + fs.writeFileSync(path.join(root, 'environments.toml'), + fs.existsSync(example) ? fs.readFileSync(example, 'utf8') : '# managed by `context-specs add`\n'); + } + fs.mkdirSync(path.join(root, 'state'), { recursive: true }); + console.log(`harness ready at ${root}`); + + if (git(root, ['remote', 'get-url', 'origin']) === null && tryRun('sh', ['-c', 'command -v gh']) !== null) { + if (await confirm('Create a private GitHub repo for this harness (gh repo create)?')) { + try { + execFileSync('gh', ['repo', 'create', path.basename(root), '--private', '--source', root, '--push'], { stdio: 'inherit' }); + } catch { + console.log('gh repo create failed — you can create and push a remote later.'); + } + } + } + console.log("\nNext: register your first environment — 'context-specs add '"); +} + +module.exports = async function init(args) { + const name = args[0]; + // Adopt mode: we ARE running from inside a harness clone (the CLI's own HOME). + if (!name) { + await adopt(HOME); + return; + } + const dest = path.resolve(name); + if (fs.existsSync(dest)) throw new Error(`${dest} already exists`); + console.log(`cloning ${TEMPLATE_URL} → ${dest}`); + execFileSync('git', ['clone', '--quiet', TEMPLATE_URL, dest], { stdio: 'inherit' }); + git(dest, ['remote', 'rename', 'origin', 'upstream']); + // Hand off to the CLONE's own CLI so paths resolve inside it. + execFileSync(process.execPath, [path.join(dest, 'bin', 'context-specs'), 'init'], { stdio: 'inherit' }); + console.log(`\ncd ${name}`); +}; From 7a3eaf9872bbf513c92d8ad957b1d7109ee2ba48 Mon Sep 17 00:00:00 2001 From: Rico Date: Sun, 5 Jul 2026 13:17:49 -0500 Subject: [PATCH 10/14] Split /harness-init into the CLI + /env-init (the Software 3.0 half) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The deterministic steps (preflight, script installs, shim skills, host worktree, dry-run, /loop startup) are gone — the context-specs CLI owns them. What remains is renamed /env-init and runs inside the environment through its symlink: .harness/env, a committed project-owned /intent (verbatim or customized — one of the two developer-owned levers), the Expert skeleton (structure-only, narrated as developer-OWNED long-term memory), AGENTS.md, local-checks.sh, bootstrap-worktree.sh generated from a template whose deterministic header re-links tier-1 skills via 'context-specs link', the reviewer choice, and the feature/env-init PR. References rewritten for the two-tier model (mental-model, dispatcher-explained, invariants-to-preserve, config-options, worktree-bootstrap); preflight.sh is absorbed by 'context-specs doctor'; counter-path wording updated in fix-local-checks, address-feedback, evaluate-sessions, learn. Co-Authored-By: Claude Fable 5 --- skills/harness/address-feedback/SKILL.md | 2 +- skills/harness/env-init/SKILL.md | 278 +++++++++++++ .../assets/AGENTS.md.template | 0 .../assets/REVIEW.md | 0 .../assets/bootstrap-worktree.template.sh | 28 ++ .../env-init/assets/expert-skeleton/SKILL.md | 41 ++ .../expert-skeleton/references/README.md | 3 + .../assets/harness-env.template | 9 +- .../assets/workflows/claude-review.yml | 0 .../references/agents-md-guidance.md | 2 +- .../env-init/references/config-options.md | 128 ++++++ .../references/dispatcher-explained.md | 253 ++++++++++++ .../references/invariants-to-preserve.md | 25 +- .../references/local-checks-design.md | 0 .../env-init/references/mental-model.md | 142 +++++++ .../references/project-discovery.md | 2 +- .../references/reviewer-options.md | 2 +- .../env-init/references/worktree-bootstrap.md | 98 +++++ skills/harness/fix-local-checks/SKILL.md | 2 +- skills/harness/harness-init/SKILL.md | 377 ------------------ .../harness-init/references/config-options.md | 142 ------- .../references/dispatcher-explained.md | 270 ------------- .../harness-init/references/mental-model.md | 110 ----- .../references/worktree-bootstrap.md | 95 ----- .../harness/harness-init/scripts/preflight.sh | 70 ---- skills/harness/learn/SKILL.md | 6 +- skills/human-loop/evaluate-sessions/SKILL.md | 4 +- .../references/trace-reading.md | 2 +- .../scripts/resolve-sessions.sh | 2 +- skills/human-loop/wiki-init/SKILL.md | 2 +- 30 files changed, 1002 insertions(+), 1093 deletions(-) create mode 100644 skills/harness/env-init/SKILL.md rename skills/harness/{harness-init => env-init}/assets/AGENTS.md.template (100%) rename skills/harness/{harness-init => env-init}/assets/REVIEW.md (100%) create mode 100644 skills/harness/env-init/assets/bootstrap-worktree.template.sh create mode 100644 skills/harness/env-init/assets/expert-skeleton/SKILL.md create mode 100644 skills/harness/env-init/assets/expert-skeleton/references/README.md rename skills/harness/{harness-init => env-init}/assets/harness-env.template (82%) rename skills/harness/{harness-init => env-init}/assets/workflows/claude-review.yml (100%) rename skills/harness/{harness-init => env-init}/references/agents-md-guidance.md (97%) create mode 100644 skills/harness/env-init/references/config-options.md create mode 100644 skills/harness/env-init/references/dispatcher-explained.md rename skills/harness/{harness-init => env-init}/references/invariants-to-preserve.md (54%) rename skills/harness/{harness-init => env-init}/references/local-checks-design.md (100%) create mode 100644 skills/harness/env-init/references/mental-model.md rename skills/harness/{harness-init => env-init}/references/project-discovery.md (98%) rename skills/harness/{harness-init => env-init}/references/reviewer-options.md (98%) create mode 100644 skills/harness/env-init/references/worktree-bootstrap.md delete mode 100644 skills/harness/harness-init/SKILL.md delete mode 100644 skills/harness/harness-init/references/config-options.md delete mode 100644 skills/harness/harness-init/references/dispatcher-explained.md delete mode 100644 skills/harness/harness-init/references/mental-model.md delete mode 100644 skills/harness/harness-init/references/worktree-bootstrap.md delete mode 100755 skills/harness/harness-init/scripts/preflight.sh diff --git a/skills/harness/address-feedback/SKILL.md b/skills/harness/address-feedback/SKILL.md index efd7c2a..a907150 100644 --- a/skills/harness/address-feedback/SKILL.md +++ b/skills/harness/address-feedback/SKILL.md @@ -123,7 +123,7 @@ git); you write no "handled" bookkeeping file. feature worktree (the dispatcher `cd`s into it; there is no print-mode `--cwd` flag), when the reviewer has unresolved findings on the PR. - **You do NOT track rounds.** The dispatcher owns the counter - (`.harness/feedback-rounds-`), increments it before **every** invocation regardless of + (`/state//feedback-rounds-`), increments it before **every** invocation regardless of bucket, and decides when to STUCK. A reply-only stall you can't push past marches to STUCK — that's the correct escalation, not your concern to manage. - **Completion:** your commits (for Clear) and replies (for the rest). The dispatcher diff --git a/skills/harness/env-init/SKILL.md b/skills/harness/env-init/SKILL.md new file mode 100644 index 0000000..3d31688 --- /dev/null +++ b/skills/harness/env-init/SKILL.md @@ -0,0 +1,278 @@ +--- +name: env-init +description: One-time setup of a project as a harness ENVIRONMENT — the Software 3.0 half that follows `context-specs add`. Generates the project-specific artifacts an LLM must read the repo to write (AGENTS.md, bootstrap-worktree.sh, local-checks.sh), installs the project-owned /intent, seeds the Expert (long-term memory) skeleton, wires the reviewer, and gathers it all onto a feature/env-init PR. Use when a developer wants to set up, initialize, or onboard a project/environment for the coding harness. +--- + +# env-init + +Stand up a project as a harness **environment**. You are an autonomous +installer: you write the artifacts end-to-end, explain the *significance* of +each as you go, and gather everything onto a `feature/env-init` PR the human +reviews and merges. + +You are the second half of a two-command setup, and the split is the point — +it is harness engineering in miniature: + +- **`context-specs add ` already ran** (deterministic CLI, tier 1): it + registered this environment with the harness repo, symlinked the canonical + skills/agents into `.claude/` (gitignored), and wrote the managed `.gitignore` + block. Everything a script can do without reading the project, a script did. +- **You do what needs judgment** (Software 3.0, tier 2): every artifact below + requires *reading this project* — its manifests, README, CI, conventions. + Scan, generate, cite the evidence. **Never invent a command you didn't see + evidence for** — ask instead. + +The tier test, if you're ever unsure what belongs to you: *could this be +written without reading the project's code?* Yes → it's the CLI's/harness +repo's, leave it alone. No → it's yours to generate here. + +## Operating mode + +Run the steps end-to-end without stopping for per-step approval — **the user +reviews everything in the `feature/env-init` PR.** Your job while installing is +to explain *significance*: for each artifact, one or two sentences on what it +is, why it exists, and what would break without it. Lead with the why, then +write the file. + +Read first: `references/mental-model.md` (so you can explain what the harness +*is*) and `references/invariants-to-preserve.md` (the rules nothing you +generate may break). Load other references as each step needs them. + +**Stop-and-confirm points — the only interruptions:** + +1. **Secret-copying** (bootstrap step) — before writing any `cp` line that + touches a `.env` or credentials file: name the exact files, confirm copy + direction (source → worktree, never reverse, never delete), get explicit consent. +2. **Reviewer choice** — wires CI and billing; the user's call. +3. **The PR merge** — after the PR opens, stop and wait for the human. + +## Preconditions + +- Run in the **developer's checkout** of the environment, on `main`, clean tree, + `origin` remote. +- `context-specs add` has run: `.claude/skills/` contains symlinks into the + harness repo (you are reading this SKILL.md through one). If it hasn't, + stop and have the user run it first; `context-specs doctor` diagnoses. + +--- + +## The install chain + +### Step 1 — Config (`.harness/env`) + +Read `references/config-options.md`. Write `.harness/env` from +`assets/harness-env.template` with the defaults (`MAX_WORKTREES=1`, per-dev +`WATCH_PATTERN` derived from `git config user.email`) unless the user has a +concrete reason otherwise. This file is **committed** — it is the environment's +project-owned dial on the tier-1 dispatcher. Runtime counters live in the +harness repo's `state//`, so there is nothing to gitignore here. + +### Step 2 — Install `/intent` (project-owned, one of the two levers) + +`/intent` is deliberately **not** symlinked like the other skills — it is a +committed, project-owned artifact, because *how well this project expresses +intent is one of the biggest levers it has*. Frame it exactly that way to the +user: **/intent and the Expert are the two developer-owned levers** — /intent +shapes what goes *into* every feature (the PRD + runnable definition of done), +the Expert shapes what every feature *knows*. Developers should expect to tune +both over time. + +Copy the canonical template from the harness repo: +`$CONTEXT_SPECS_HOME/skills/human-loop/intent/` → `.claude/skills/intent/` +(SKILL.md + references/). (`CONTEXT_SPECS_HOME` = the symlinks' target root: +`readlink .claude/skills/spec-planning` and strip `/skills/...`.) Then offer +the choice: + +- **Generic (fine to start):** install verbatim; customize later by editing — + it's the project's file either way. +- **Customized now:** scan the repo and tailor the marked hackable seams — + `references/prd-template.md` (project DoD conventions: what can + `run-prd-test.sh` actually exercise here — e2e harness? LLM-judge hybrid?), + `references/elicitation.md` (domain vocabulary, the questions this project's + features always end up needing), `references/runner-recipes.md` (this + project's test idioms). Cite the scan evidence for every tailored line. + +### Step 3 — Seed the Expert (long-term memory) skeleton + +Copy `assets/expert-skeleton/` → `.claude/skills/expert/`. Structure only — +empty routing table, no invented content: shards are added by `/learn` (post- +merge), by the implementer's Reflect step (post-slice), **and by the developer +directly**. + +Narrate the ownership model loudly; it is the heart of the system: the Expert +is the project's long-term memory, and **the developer owns it**. The loops +are continuous helpers that file things into it; editing it directly is +expected, not exceptional. Long-term memory informs short-term memory — every +`/spec-planning` run reads this to plan the next feature — so improving a shard +improves every future feature. The skeleton's conventions (one topic per shard, +prefix names, `USE WHEN:` openers, routing table inline in SKILL.md) exist so a +weak plan can be traced back to the specific shard that should have taught it. + +### Step 4 — `AGENTS.md` (Software 3.0) + +Read `references/agents-md-guidance.md` and `references/project-discovery.md`. +Scan the repo, fill `assets/AGENTS.md.template`'s bracketed parts (project name, +the verification-layer tooling), keep the rest verbatim. AGENTS.md is the +neutral, eagerly-loaded contract — a map that points into the Expert, not an +encyclopedia; keep it tight (~150 lines). Cite the scan finding behind each +filled-in line. The Expert section is intentional even while the Expert is a +skeleton. + +### Step 5 — `scripts/local-checks.sh` (optional, Software 3.0) + +The deterministic gate the dispatcher runs before opening a PR (two-strike: +`local-checks.sh fix` → `/fix-local-checks` → STUCK). Cheapest place to catch +correctness issues — left of the reviewer and CI. **Read +`references/local-checks-design.md` first** and narrate the *why*; the user +owns and tunes this script. Two responsibilities: + +- **Wire the project's deterministic checks** — lint/format (with a `fix` + subcommand), typecheck, the **fast** unit suite (slow/integration → CI), a + **skip-detection** check, and everything in `scripts/lints/`. Prefer commands + the project already defines. +- **Propose custom correctness lints** from the codebase as-is (snapshot + discovery), behind the five guards in the reference. + +The gate proves **correctness, not coverage** — block only +correctness/structural, warn on legibility. The **skip rule** is load-bearing: +an agent may never add a test-skip marker; a legitimate skip is the human's +call at STUCK. If the project has no deterministic checks, skip this step — +the dispatcher treats the script as absent and works fine. + +### Step 6 — `scripts/bootstrap-worktree.sh` (Software 3.0 below the line) + +Read `references/worktree-bootstrap.md`. Generate from +`assets/bootstrap-worktree.template.sh`, whose **deterministic header is +verbatim and untouchable**: it calls `context-specs link` so every fresh +worktree gets the tier-1 skill symlinks (gitignored symlinks never materialize +in new worktrees — without this line, every headless step would run skill-less). +The dispatcher exports `CONTEXT_SPECS_HOME` when it calls this script, so +nothing machine-specific is committed. + +You generate only the section **below the marker**: copy gitignored runtime +files, install dependencies, run codegen — discovered from +README/CI/manifests (`references/project-discovery.md`); if discovery is thin, +ask the user how they set the project up on a fresh machine. Idempotent, +non-interactive, well-commented. + +**The secret-copy lines are stop-and-confirm point 1** — see Operating mode. +If the project has no gitignored secrets, skip that part and say so. + +### Step 7 — Reviewer (stop-and-confirm point 2) + +Read `references/reviewer-options.md`. Three paths (self-hosted via +`claude-code-action` = recommended default; managed Code Review; none); +switching later is cheap. **Present the paths, recommend self-hosted, and +confirm — including auth — before configuring anything.** + +- **Self-hosted:** copy `assets/REVIEW.md` → repo root and + `assets/workflows/claude-review.yml` → `.github/workflows/`, then: + 1. **Pick auth with the user:** subscription (`CLAUDE_CODE_OAUTH_TOKEN` from + `claude setup-token`) vs metered API (`ANTHROPIC_API_KEY`). Uncomment the + chosen line, have them add the matching repo secret. + 2. **Pin the action** to the current release tag + (`gh release view --repo anthropics/claude-code-action`). + 3. **Tell them the v1 same-content rule:** the workflow only takes effect + once merged to `main`; it can't be tested from a feature branch. +- **Managed:** copy `REVIEW.md`; give the GitHub App install instructions. +- **None:** create nothing; set `REVIEW_CLEAN_MARKER=` (empty) in + `.harness/env` so the dispatcher converges at PR-open. + +**Convergence marker (both reviewer paths):** `REVIEW.md` instructs the +reviewer to post a PR comment containing `HARNESS_REVIEW_CLEAN` once no +Important findings remain; the dispatcher sees it and hands the PR to the human +for `/evaluate-pr`. Configurable via `REVIEW_CLEAN_MARKER` (must match +REVIEW.md). If the reviewer never posts it, the feedback loop STUCKs at +`FEEDBACK_CAP` instead — a clean PR the human merges. + +### Step 8 — Commit on `feature/env-init`, push, open PR, wait for merge + +**Hard rule: never commit setup artifacts directly to `main`.** Everything from +Steps 1–7 — plus the `.gitignore` block `context-specs add` wrote — lands on +`feature/env-init` and reaches `main` only via a merged PR: the whole install +in one reviewable diff. + +``` +git checkout -b feature/env-init +git add .harness/env .gitignore scripts/ AGENTS.md REVIEW.md .github/ \ + .claude/skills/intent .claude/skills/expert +git commit -m "harness: environment setup via env-init" +git push -u origin feature/env-init +gh pr create --base main --head feature/env-init \ + --title "harness: environment setup" --fill +``` + +(The symlinked skills are gitignored and stay out of the diff — that's the +tier split showing up in git: canonical stays in the harness repo, project-owned +gets committed here.) + +Walk the user through the PR, then **stop and ask them to merge before +continuing (stop-and-confirm point 3).** Why merge first: the dispatcher works +entirely through `origin` — it claims PRDs from origin refs and creates +worktrees from `origin/feature/*` branches that fork off `main`. Until this +merge lands, those branches would contain none of these artifacts (no +`.harness/env`, no bootstrap, no Expert), so the first feature would run +against an unconfigured project. + +### Step 9 — Prove the wiring, then hand off to the CLI + +Once merged (`git fetch && git pull`), have the user run, from the harness repo: + +``` +context-specs doctor # every check green for this environment +context-specs run # one foreground tick: fetch, find nothing, exit idle +``` + +A clean no-op `run` proves the whole chain — registry, dispatcher, config, +worktree base — without doing any work. Then the daily flow: + +``` +context-specs start # background supervisor: build loop + memory loop +``` + +1. **`/intent`** in this checkout → confirm a PRD → walk away. The harness + picks it up (a tick that advances work re-fires immediately — real work + drains at machine speed; idle ticks nap the interval). +2. Either: the reviewer converges → the harness posts **"Ready for your + review"** with the build-session trail → run **`/evaluate-pr `**, + understand it, merge. Or: a step hits its cap → **STUCK** post with the + session log + diagnosis-first checklist. **Your first job is the context + defect, not the code** — find which AGENTS.md / Expert / spec / PRD content + misled the agent, correct it on the branch, then fix the code, merge. +3. After each merge, the memory loop raises a `learn/` PR — the project + updating its own long-term memory. Review it with the same care as code: + it decides what every future feature knows. + +`context-specs status` shows every environment's features and phases; +`context-specs logs -f` follows the loop. + +--- + +## Inner skill dependency + +The dispatcher invokes `/spec-planning`, `/spec-validate`, `/implement-mainspec`, +`/fix-local-checks`, and `/address-feedback`; the memory loop invokes `/learn`. +All arrive as symlinks from the harness repo via `context-specs add` — verify +they resolve (`context-specs doctor`). Two are **human-invoked**: `/intent` +(installed by Step 2 as project-owned) and `/evaluate-pr`. env-init generates +the project-specific artifacts; it does not author skills. + +## Re-running + +Safe to re-run. For canonical files (REVIEW.md, workflow, the bootstrap +header), diff and offer to update. For generated files (`AGENTS.md`, +`local-checks.sh`, the bootstrap body, /intent customizations), re-scan and +show a diff rather than overwriting blind. Never overwrite the Expert's +references/ — that is live memory now, not yours. If `feature/env-init` +already exists from a prior run, update that branch rather than creating a +fresh one. + +## Hard rules (from invariants-to-preserve.md) + +- Never generate an LLM call into the dispatcher's decision path (Invariant 5). +- Never replace the atomic-rename claim with a marker/lock file (Invariant 2/7). +- Never generate a "go backward" / sentinel-deleting step (Invariant 9). +- `bootstrap-worktree.sh` copies secrets source→worktree only, never deletes, + never the reverse (Invariant 6) — and its `context-specs link` header stays. +- Never commit setup artifacts directly to `main` — everything rides the + `feature/env-init` PR (Step 8). diff --git a/skills/harness/harness-init/assets/AGENTS.md.template b/skills/harness/env-init/assets/AGENTS.md.template similarity index 100% rename from skills/harness/harness-init/assets/AGENTS.md.template rename to skills/harness/env-init/assets/AGENTS.md.template diff --git a/skills/harness/harness-init/assets/REVIEW.md b/skills/harness/env-init/assets/REVIEW.md similarity index 100% rename from skills/harness/harness-init/assets/REVIEW.md rename to skills/harness/env-init/assets/REVIEW.md diff --git a/skills/harness/env-init/assets/bootstrap-worktree.template.sh b/skills/harness/env-init/assets/bootstrap-worktree.template.sh new file mode 100644 index 0000000..3e65272 --- /dev/null +++ b/skills/harness/env-init/assets/bootstrap-worktree.template.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# bootstrap-worktree.sh — make a fresh git worktree runnable for this project. +# +# The dispatcher runs this after every `git worktree add`. A bare worktree has +# tracked files only: no dependencies, no secrets, no generated code — and no +# tier-1 skill symlinks (gitignored symlinks never materialize in new +# worktrees). This script closes that gap. It must be IDEMPOTENT (it re-runs on +# worktree re-attach) and NON-INTERACTIVE (it runs unattended inside the loop). +# +# Usage: scripts/bootstrap-worktree.sh +set -euo pipefail +WT="${1:?usage: bootstrap-worktree.sh }" + +# --- context-specs deterministic section (do not edit or remove) ------------- +# Re-create the tier-1 skill/agent symlinks in the new worktree so headless +# skills resolve there. CONTEXT_SPECS_HOME is exported by the dispatcher (which +# derives it from its own location); a human running this by hand exports it to +# their harness repo path. Idempotent and fast. +"${CONTEXT_SPECS_HOME:?export CONTEXT_SPECS_HOME=, or invoke via the harness}/bin/context-specs" link "$WT" +# --- project-specific provisioning below (generated by /env-init) ------------ + +# [Generated per project by /env-init — typical steps, in order: +# 1. copy gitignored runtime files (.env, credentials) from the source checkout +# (derive it via `git -C "$WT" rev-parse --git-common-dir` → its parent); +# copy direction is ALWAYS source → worktree, never the reverse, never delete +# 2. install dependencies with the lockfile-frozen flavor (npm ci, uv sync, ...) +# 3. run codegen the project needs before it can run (prisma generate, ...) +# Every step gets a one-line comment saying what it provisions and why.] diff --git a/skills/harness/env-init/assets/expert-skeleton/SKILL.md b/skills/harness/env-init/assets/expert-skeleton/SKILL.md new file mode 100644 index 0000000..5db97e4 --- /dev/null +++ b/skills/harness/env-init/assets/expert-skeleton/SKILL.md @@ -0,0 +1,41 @@ +--- +name: expert +description: This project's long-term memory — how to run, validate, and extend it; its architecture, patterns, hard invariants, and worked examples. Consult when planning a feature, validating a spec, implementing a slice, or writing intent for this project. Routing table below points to one small reference file per topic. +--- + +# The Expert — this project's long-term memory + + + +## How to use this memory + +Scan the routing table, open **only** the reference files whose `USE WHEN` matches +the task at hand. Each file is one topic; files cross-link with `[[wikilinks]]` +(resolve `[[name]]` to `references/name.md`). Do not page through everything. + +## Routing table + + + +| Reference | USE WHEN | +|---|---| +| _(empty — the first /learn, Reflect, or your own edit adds the first shard)_ | | + +## Writing to this memory + +- **One topic per file**, named `-.md`, opening with a `USE WHEN:` line. +- **Ground truth only** — facts true of the code on `main`, cited (file paths, shas). +- **Reconcile, don't accumulate** — a change that stales a shard edits or deletes it. +- Add the routing-table line in the same commit as the shard. diff --git a/skills/harness/env-init/assets/expert-skeleton/references/README.md b/skills/harness/env-init/assets/expert-skeleton/references/README.md new file mode 100644 index 0000000..d366e94 --- /dev/null +++ b/skills/harness/env-init/assets/expert-skeleton/references/README.md @@ -0,0 +1,3 @@ +# references/ + +One small file per topic, named `-.md` (how-to-, concept-, pattern-, invariant-, example-), each opening with a `USE WHEN:` line and listed in the SKILL.md routing table. Created by /learn, Reflect, and you. diff --git a/skills/harness/harness-init/assets/harness-env.template b/skills/harness/env-init/assets/harness-env.template similarity index 82% rename from skills/harness/harness-init/assets/harness-env.template rename to skills/harness/env-init/assets/harness-env.template index 9120043..8a43e66 100644 --- a/skills/harness/harness-init/assets/harness-env.template +++ b/skills/harness/env-init/assets/harness-env.template @@ -1,8 +1,9 @@ -# .harness/env — harness configuration, sourced by scripts/poll-and-dispatch.sh +# .harness/env — this environment's harness configuration. # -# This file is committed so a team's checkouts share defaults. The per-feature -# COUNTER files in .harness/ (feedback-rounds-*, local-check-attempts-*, -# last-main-sha) are runtime state and are gitignored — never commit those. +# Sourced by the tier-1 dispatcher (/scripts/poll-and-dispatch.sh +# and learn-dispatch.sh) on every tick. Committed so a team's checkouts share +# defaults. Runtime state (retry counters, stuck sentinels, session logs) lives +# in the harness repo under state//, not in this repo. # How many features the harness works in parallel. # 1 = single worktree, FIFO (recommended default for a single developer). diff --git a/skills/harness/harness-init/assets/workflows/claude-review.yml b/skills/harness/env-init/assets/workflows/claude-review.yml similarity index 100% rename from skills/harness/harness-init/assets/workflows/claude-review.yml rename to skills/harness/env-init/assets/workflows/claude-review.yml diff --git a/skills/harness/harness-init/references/agents-md-guidance.md b/skills/harness/env-init/references/agents-md-guidance.md similarity index 97% rename from skills/harness/harness-init/references/agents-md-guidance.md rename to skills/harness/env-init/references/agents-md-guidance.md index 767b766..e51215e 100644 --- a/skills/harness/harness-init/references/agents-md-guidance.md +++ b/skills/harness/env-init/references/agents-md-guidance.md @@ -9,7 +9,7 @@ non-bypassable verification layers. Using the neutral file (rather than a tool-specific one) also keeps the project's memory portable and its own — no lock-in to a single tool. -harness-init generates it from `assets/AGENTS.md.template` plus a codebase scan +env-init generates it from `assets/AGENTS.md.template` plus a codebase scan (project-discovery.md). Most of the template is canonical and stays verbatim; only the bracketed parts are filled from the scan. diff --git a/skills/harness/env-init/references/config-options.md b/skills/harness/env-init/references/config-options.md new file mode 100644 index 0000000..5712c3d --- /dev/null +++ b/skills/harness/env-init/references/config-options.md @@ -0,0 +1,128 @@ +# Config options — `.harness/env` + +The harness has a small, deliberately tiny config surface. Per-environment +knobs live in the environment's committed `.harness/env` (sourced by the tier-1 +dispatcher on every tick); scheduling knobs live with the CLI. When you walk +the user through config, explain each knob's tradeoff and recommend the +default; only change a default if the user has a concrete reason. + +## The knobs (`.harness/env`, committed in the environment) + +### `MAX_WORKTREES` (default `1`) + +How many features the harness works in parallel *in this environment*. + +- **`1` (recommended default).** Single worktree, FIFO. One feature at a time. + No disk multiplication, simplest mental model. Right for essentially every + single-developer project. (Parallelism across *environments* is free — each + has its own supervisor.) +- **`2`+.** Bounded parallelism. Each concurrent feature gets its own sibling + worktree, so disk and rebuild cost multiply. + +In-flight work always continues regardless of this value — it caps *new intake*, +not continuation. + +### `WATCH_PATTERN` (default `prd//*`) + +Which PRD branches this harness claims. `` derives from +`git config user.email` (the part before `@`). + +| Mode | Pattern | Behavior | When | +|------|---------|----------|------| +| **Per-dev (default)** | `prd//*` | Each dev's harness claims only their own PRDs, on their own machine, their own API quota. | Default. Best attribution, cost, and observability. | +| **Shared pool** | `prd/*/*` | All harnesses race for everything; atomic rename keeps it safe. | A team deliberately sharing a work pool. | + +### STUCK caps + +Bounded-retry circuit breakers — every step has one, so the loop can't run away. +At cap, the dispatcher signals STUCK on the PR (opening it as a draft if no PR +exists yet) with the session log + a diagnosis-first checklist, and halts that +feature. A STUCK-only tick exits 0, so a stuck environment never hot-loops. + +| Var | Default | Step it bounds | +|---|---|---| +| `PLANNING_CAP` | 2 | `/spec-planning` | +| `VALIDATE_CAP` | 2 | `/spec-validate` | +| `IMPLEMENT_CAP` | 3 | `/implement-mainspec` (PRD runner keeps failing) | +| `LOCAL_CHECKS_CAP` | 2 | `scripts/local-checks.sh` two-strike | +| `FEEDBACK_CAP` | 5 | reviewer feedback rounds | + +### `REVIEW_CLEAN_MARKER` (convergence signal) + +Default `HARNESS_REVIEW_CLEAN`. When the reviewer has no Important findings left, +`REVIEW.md` instructs it to post a PR comment containing this token; the dispatcher +(`reviewer_converged`) sees it and hands the PR to the human for `/evaluate-pr`. +Detection is intentionally simple — marker present → converge. If the reviewer +never posts it, the feedback loop reaches `FEEDBACK_CAP` and STUCKs instead (a +clean PR the human merges). Set it **empty** when there is **no reviewer**, so +the dispatcher converges at PR-open. Must match `REVIEW.md`. + +### `CLAUDE_PERM_ARGS` + +Headless permission posture for the `claude -p` subprocesses; see the template's +comments. Default `( --permission-mode auto )`. + +## Scheduling knobs (the CLI's, not `.harness/env`) + +- **Build interval** — `INTERVAL` env var on `context-specs start`, or a per-env + `interval` in `environments.toml`. Default 300s. This is only the *idle* poll + rate: a tick that advanced work (exit 10) re-fires immediately, so real work + drains at machine speed regardless of the interval. +- **Learn interval** — `LEARN_INTERVAL`, default 600s. The memory loop can tick + lazily: it only acts when `origin/main` has advanced past the watermark AND no + `learn/` PR is open. Most ticks are cheap no-ops. + +Both are UX knobs, not correctness ones — the loops self-serialize (per-env +locks) and re-derive their state every tick, so a missed or slow tick never +corrupts anything. + +### The memory loop's watermark (`refs/harness/last-learned`) + +Not a config value — a git **ref** on the environment's remote, the memory +loop's only durable state. It records how far into `main`'s history `/learn` +has digested. `learn-dispatch.sh` reads it as the `--since` for the next run +and advances it (atomic `--force-with-lease`) after each run. It lives in its +own ref namespace, so it survives `learn/` branch deletion and is shared +across nodes. To force a full re-learn, delete the ref +(`git push origin :refs/harness/last-learned`) or run `/learn --rebuild` by hand. + +## What does NOT go in config + +- **The claim mechanism** — the atomic rename, hardcoded. Not configurable. +- **Completion signals** — sentinel files, hardcoded in the dispatcher. +- **The pipeline order** — the `if/elif` chain in the tier-1 dispatcher, edited + there (see dispatcher-explained.md), not a config value. +- **Where state lives** — always the harness repo's `state//`. + +## Runtime state — `state//` in the harness repo + +Holds per-environment runtime state, all re-derivable, none of it secret, all +gitignored in the harness repo (nothing of it lives in the environment): + +- `tick.lock`, `learn.lock` — per-env `flock` files (tick serialization). +- `planning-attempts-`, `validate-attempts-`, `implement-attempts-`, + `local-check-attempts-`, `feedback-rounds-` — per-feature retry counters + (each gates a STUCK circuit breaker). +- `stuck-`, `stuck-output-.log`, `stuck-body-.md` — written when a cap + hits; cleared on merge/close. +- `human-review-`, `human-review-posted-`, `human-review-body-.md` — + written at reviewer convergence; cleared on merge/close. +- `sessions-.tsv` — every `claude -p` invocation for this feature (timestamp, + step, attempt, session_id, exit, duration). The STUCK PR body quotes its tail + so the human can open the trace by session id. +- `supervisor.pid`, `logs/{build,learn,supervisor}.log` — the CLI's. + +Deleting this directory is safe (it unregisters nothing): counters reset, +sentinels re-derive from git and PR state on the next tick. + +The environment's `.harness/env` is the one committed piece — commit it so a +team's checkouts share defaults. + +## Multi-developer reminder + +Per-dev is the default for a reason (attribution, cost isolation, "my harness is +my assistant" mental model). The harness *repo* is shareable — a team improves +skills and scripts in one place, while each dev's registry (`environments.toml`) +and state stay per-machine. Don't steer a user to shared-pool claiming unless +they explicitly describe a shared-queue workflow; when a team truly outgrows +local harnesses, the move is a server/CI harness. diff --git a/skills/harness/env-init/references/dispatcher-explained.md b/skills/harness/env-init/references/dispatcher-explained.md new file mode 100644 index 0000000..7129be0 --- /dev/null +++ b/skills/harness/env-init/references/dispatcher-explained.md @@ -0,0 +1,253 @@ +# The dispatcher, explained + +When you explain the harness to the user, walk them through the dispatcher +using this file. The goal: the user understands every section well enough to +decide whether to tweak it (in the **harness repo** — the dispatcher is tier 1, +shared by every environment). Never present it as a black box. + +## What it is + +`/scripts/poll-and-dispatch.sh [env-name]` — bash, +`git`, and `gh`. No LLM in the decision path. It runs once per tick, invoked by +the `context-specs` supervisor (or by hand via `context-specs run`). The +`if/elif` chain is the state machine; the artifacts on disk are the state. It +operates on the environment entirely through `git -C ` (refs, +fetches, pushes, sibling worktrees) and keeps its runtime state in the harness +repo under `state//`. + +**The exit code is the scheduling protocol:** + +| Exit | Means | The supervisor does | +|------|-------|---------------------| +| `0` | idle — no transitions (includes STUCK-only ticks) | sleep the interval (default 5m) | +| `10` | advanced — at least one transition happened | re-invoke IMMEDIATELY (drain) | +| else | error | exponential backoff, capped at 1h | + +Drain-on-10 is why a claimed PRD marches through planning → validate → +implement at machine speed instead of one step per 5 minutes; idle polling +stays cheap. STUCK deliberately exits 0 — a stuck environment must never +hot-loop. + +## The seven load-bearing properties + +Explain these as the "why it's safe" of the script. Each maps to an invariant. + +1. **One transition per tick per branch.** The `if/elif` fires at most one + branch. Next tick, the artifact this tick wrote satisfies the condition and + the *next* `elif` fires. Forward, one step at a time. (Inv 5) +2. **Artifacts are the only state.** A sentinel existing IS that phase being + done. No checkpoint file. Crash recovery is free — next tick re-derives from + disk. (Inv 1 + 4) Most sentinels are written by the skills; `specs//.prd-passed` + is the exception — the *dispatcher* commits+pushes it the first time + `run-prd-test.sh` exits 0, so a runner that shells out to an LLM-as-judge runs + once instead of every tick (and can't non-deterministically re-kick implement). +3. **Wipe + HEAD-check before every advance.** `git reset --hard && git clean + -fd` discards a crashed skill's uncommitted mess; the HEAD guard skips any + worktree whose branch doesn't match the feature being advanced, so a + manually-checked-out branch is never clobbered. Runs only in per-feature + worktrees — never in the developer's clone. (Inv 3 + 6) +4. **Dispatcher never invokes an LLM directly.** It only spawns `claude -p` + subprocesses or shells to `git`/`gh`. Each subprocess is a fresh process and + a clean context window. (Inv 5) +5. **Local checks are optional and bounded.** If the environment has + `scripts/local-checks.sh`, the PR is gated on it with a two-strike retry + (auto-fix, then focused LLM fix, then stop). No script = gate skipped. (Inv 8) +6. **`MAX_WORKTREES` is the one concurrency knob.** Default 1 = FIFO single + worktree. Claims are lazy: PRDs over capacity stay in `prd//*` as the + visible queue. In-flight work always continues regardless of cap changes. + (Inv 2 + 3) +7. **Convergence has its own exit — HUMAN_REVIEW — separate from STUCK.** The + review loop's healthy end is the reviewer posting `REVIEW_CLEAN_MARKER`; + `reviewer_converged` sees it and writes `human-review-`, the guard posts the + session trail once and halts the feature for the human's `/evaluate-pr`. The + marker (not sticky review state) is the signal, so a clean PR can't false-STUCK + on a stale `COMMENTED` review. If the reviewer never marks clean, the feedback + cap STUCKs instead — fine, the human merges. + +## Section-by-section map + +| Section | What | Tweakable? | +|---------|------|------------| +| derivation block | `ENV_PATH`, `ENV_NAME`, `STATE_DIR`, `WORKTREE_BASE`, `TRANSITIONS` | No — the argv contract the supervisor calls. `WORKTREE_BASE` derives from the env's path, so per-feature paths are `-harness-` siblings. | +| `flock -n` | per-env lock on `state//tick.lock` | No — serializes ticks per environment; the script is shared, so the lock must not be. | +| config | `SLUG`, `WATCH`, caps, marker | Via the env's committed `.harness/env`, not by editing here. | +| `has_prd()` | Invariant-2 ownership filter | No — defines what "harness-owned" means. | +| step 1 | re-attach in-flight worktrees | The `bootstrap_worktree` hook call is the provisioning hook (see below). The PR-state **liveness gate** (skip `MERGED`/`CLOSED` features) is load-bearing — don't drop it; see "Liveness" below. | +| step 2 | lazy claim up to capacity | No — atomic rename is the claim lock. | +| step 3 | advance each feature one step | **This is where you add/remove pipeline steps** — one `elif` per step. | +| step 4 | cleanup merged/closed PRs (worktree + local branch + counters) | Safe to extend (e.g., notify on cleanup). | +| exit block | `TRANSITIONS > 0 → exit 10` | No — it IS the supervisor protocol. New steps that advance work should bump `TRANSITIONS` (run_claude does it for you). | +| post-merge `/learn` | **NOT in this script** — runs in the separate memory loop (`learn-dispatch.sh`). See "The memory loop" below. | Watermark/idempotency live there. | +| helpers (shared) | `run_claude` (session-tagged invocation + TSV log + transition count), `render_sessions_table`, `ghe` (gh-in-the-env), `worktree_for`, `bootstrap_worktree` — live in `harness-lib.sh`, both loops use them. | Edit `run_claude` in one place (e.g. the `--session-id` swap). | +| helpers (dispatcher) | `signal_stuck`, `signal_human_review`, `reviewer_converged`, `has_prd` | Used by §3 steps that call `claude -p`, hit a cap, or detect convergence. | + +One wrapper deserves a callout: **every `gh` call goes through `ghe()`**, which +runs gh with the *environment* as cwd. gh resolves "which GitHub repo" from its +working directory, and the dispatcher's cwd is the harness repo — the wrong +repo. A bare `gh` call here would silently act on the harness repo and its +`2>/dev/null` guard would hide it. Keep new gh calls behind `ghe`. + +## The bootstrap hook — environment-owned worktree provisioning + +A bare worktree has no `node_modules`, no `.env`, no generated code — **and no +tier-1 skill symlinks** (gitignored symlinks never materialize in new +worktrees) — so slice signals and the PRD runner would fail for reasons +unrelated to the feature. So immediately after every `git worktree add`, the +dispatcher runs the environment's `scripts/bootstrap-worktree.sh "$wt"` if it +exists and is executable, exporting `CONTEXT_SPECS_HOME` so the script's +deterministic header can call `context-specs link` on the new worktree. The +hook itself is canonical; the script it calls is **environment-owned** — +env-init generates it per project (see `worktree-bootstrap.md`). + +Make sure the user knows: this hook is why the per-feature worktrees the +harness spins up are actually runnable *and* have their skills. + +## Liveness — branch existence is not in-flight (the step-1 PR-state gate) + +`has_prd()` answers *ownership* ("is this a harness feature?"), not *liveness* +("is there still work to do?"). A `feature/` whose PR has **merged** keeps both +its branch (GitHub's delete-on-merge is off by default) and its committed PRD — +so `has_prd()` stays true forever. Without a liveness check, step 1 re-attaches +that finished feature as in-flight on *every* tick: step 3 re-fires +`/address-feedback` on the merged PR (wasted tokens), and the phantom occupies a +`MAX_WORKTREES` slot so a fresh PRD sits unclaimed. The fix is one gate in step +1, right after `has_prd`: `ghe pr view` the feature's PR and `continue` past any +`MERGED`/`CLOSED` one. Notes: + +- **No branch deletion on the remote.** The harness stops treating it as live + work; consumers keep their branch-retention policy. (The *local* branch in the + developer's clone IS deleted at cleanup — worktree-add created it, and a stale + one would collide when a feature name is reused.) +- **Fail-safe on empty state.** A feature in a pre-PR phase has no PR, and a + transient `gh` outage also returns empty — both are kept in-flight so live + work is never silently dropped. +- **Forward-only (Inv 9).** Merged is terminal; the gate only skips, never rewinds. + +## How the dispatcher stays fresh (no tick wrapper anymore) + +Earlier revisions installed the dispatcher *inside* each project and needed a +wrapper (`harness-tick.sh`) to resync it every tick without overwriting its own +running file. The two-tier split dissolves all of that: the dispatcher lives in +the harness repo and never operates on the repo containing its own bytes. +Updating it is ordinary tool hygiene — `git pull upstream` in the harness repo +(or `context-specs` updates), applied between ticks. Feature **pipeline** skills +never needed a sync at all: they run inside per-feature worktrees that branch +from the PRD branch, so new features pick up skill updates on their own. + +## The memory loop — `/learn` as its own loop (`learn-dispatch.sh`) + +`/learn` is **not** a dispatcher step. It runs in a second, independent loop the +supervisor schedules on its own interval (default 10m): +`scripts/learn-dispatch.sh `. This is the deliberate decoupling that +keeps a multi-minute Expert bootstrap from blocking (or being blocked by) the +build loop. The two loops share nothing but git (Inv 1 + 7): separate locks +(`state//learn.lock` vs `tick.lock`), separate worktrees. + +What `learn-dispatch.sh` does each tick: + +1. `flock -n` its own per-env lock (a long bootstrap just no-ops later ticks). +2. `git -C fetch` `main` **and** the watermark ref namespace + (`+refs/harness/*:refs/harness/*`). Refs only — never a working tree. +3. **Pause** if a `learn/` PR is already open (`ghe pr list …`): memory + edits serialize behind human review. Nothing is queued — the backlog is + implicit in `(watermark, origin/main)` and recomputed every tick. +4. Compute `since = refs/harness/last-learned` (or a bounded look-back on the + first run), `to = origin/main`; if equal, no-op. +5. `git ls-remote origin learn/` idempotency (cross-node first-to-push-wins). +6. Ensure the dedicated, **reused** `-harness-learn` worktree exists + (create + `bootstrap_worktree` on first run), re-run `context-specs link` on + it (persistent worktree, evolving skill set), reset it to clean + `origin/main`, check out `learn/`. +7. Run `/learn --since --sha ` there. `/learn` writes memory, + pushes the branch, opens the PR. +8. `signal_learn_review` posts the session trail on the PR (if one opened). +9. Advance `refs/harness/last-learned` to `` with an atomic CAS + (`--force-with-lease`) — the same first-to-push-wins primitive used to claim + PRDs. The advance happens whether or not a PR opened (a no-op merge is still + "learned"). + +**Why a ref watermark, not a state file.** A ref lives in its own namespace +nothing cleans, so it survives `learn/` branch deletion; it's on the +remote, so it's shared across nodes; and `--force-with-lease` gives a lock-free +compare-and-swap. To force a full re-learn: delete the ref or run +`/learn --rebuild` by hand. + +## Human-steering points: Evaluate (HUMAN_REVIEW) and STUCK + +The human steers the machine at three touchpoints (confirm a PRD, +evaluate-then-merge a PR, unstick a STUCK). Two of those live in this script. + +**HUMAN_REVIEW (the healthy one).** When the reviewer converges (posts +`REVIEW_CLEAN_MARKER`), `reviewer_converged` writes `human-review-`; the guard +posts the build-session trail once and halts the feature. The human runs +`/evaluate-pr` to walk the change, run it, and merge (or fix-and-push, or close). +The loop does not re-engage — the human is the last mile. + +**STUCK (the failure one).** Memory still has its post-merge write path — +`/learn` in the memory loop, ground truth only. There is no separate write path +for failed features. Instead, **STUCK** (a step in §3 hitting its cap) is a +first-class escalation: the dispatcher posts to the PR (opening it as a draft if +needed) with the session log, the failing output tail, and a diagnosis-first +checklist, then halts the feature. The human's first job at STUCK is to identify +the **context defect** (which `AGENTS.md` / Expert / spec / PRD content misled +the agent), correct it on the branch, *then* fix the code, *then* merge. Those +context corrections ride into main with the merge, where `/learn` picks them up. + +## The session log + STUCK signal + +`run_claude` and `render_sessions_table` are **shared** (in `harness-lib.sh`); +the rest are dispatcher-local: + +- **`run_claude ""`** (shared) — + wraps every `claude -p` call. `cd`s into the worktree `` first (there is + no print-mode `--cwd` flag, and the `cd` is what gives the skill its + `.claude/` command + `AGENTS.md` discovery). Generates a UUID session id, runs + `claude -p --session-id "${CLAUDE_PERM_ARGS[@]}"`, bumps the dispatcher's + `TRANSITIONS` counter, and appends + `\t\t\t\t\t` to + `state//sessions-.tsv` (cleared on merge/close). A non-zero + skill exit is recorded in the row but never aborts the tick (`return 0`). +- **`signal_stuck [output-file]`** — touches the stuck + sentinel, composes a PR body (step, cap, session-log tail, optional failing + output tail, diagnosis-first checklist), and opens a draft PR or comments on + the existing one. The single human-facing surface for failures. +- **`reviewer_converged `** — true iff a PR comment contains + `REVIEW_CLEAN_MARKER`. One `ghe` call, no LLM. Empty marker = no reviewer → false. +- **`signal_human_review `** — the convergence counterpart: posts the + "Ready for your review" comment with the session trail for `/evaluate-pr`. +- **`signal_learn_review `** — lives in **`learn-dispatch.sh`**: + after `/learn` opens its `learn/` PR, posts the headless session trail + framed for troubleshooting *why* `/learn` routed each fact as it did. + +If your `claude -p` version doesn't support `--session-id`, swap that flag for +`--output-format json` and parse `session_id` from stdout — `run_claude` is the +one place to change. + +## Common tweaks to offer + +- **Add a pipeline step** (e.g. `/security-review` between validate and + implement): insert one `elif` in step 3 with its own sentinel check, its own + `_CAP`, and a `run_claude` / `signal_stuck` pair like the others. + Remember this edits the harness repo — every environment gets the new step. +- **STUCK caps**: `PLANNING_CAP`, `VALIDATE_CAP`, `IMPLEMENT_CAP`, + `LOCAL_CHECKS_CAP`, `FEEDBACK_CAP` — per-environment, in `.harness/env`. +- **Tick cadence**: `INTERVAL` / `LEARN_INTERVAL` env vars on + `context-specs start`, or a per-env `interval` in `environments.toml`. UX + knobs, not correctness ones — the loops self-serialize and re-derive state + every tick. + +## What NOT to let the user do + +- Add `&` to any `claude -p` call (breaks synchronous one-step discipline). +- Add an LLM call to the decision logic (breaks Inv 5, makes it non-reproducible + and a cost surface). +- Remove the wipe or the HEAD guard (breaks crash recovery and Inv 6). +- Replace the atomic-rename claim with a marker file (breaks Inv 2 + 7). +- Call `gh` directly instead of `ghe` (acts on the wrong repo, silently). +- Exit 10 from an error path, or bump `TRANSITIONS` at STUCK (either would make + the supervisor hot-loop a broken environment). +- Fold `/learn` back into the dispatcher as a step — that re-couples the loops, + so a multi-minute Expert bootstrap again blocks every feature step. +- Make `learn-dispatch.sh` do working-tree ops in the developer's clone instead + of `-harness-learn` — the developer's tree is never the harness's + surface (Inv 6). diff --git a/skills/harness/harness-init/references/invariants-to-preserve.md b/skills/harness/env-init/references/invariants-to-preserve.md similarity index 54% rename from skills/harness/harness-init/references/invariants-to-preserve.md rename to skills/harness/env-init/references/invariants-to-preserve.md index 9f36270..275b684 100644 --- a/skills/harness/harness-init/references/invariants-to-preserve.md +++ b/skills/harness/env-init/references/invariants-to-preserve.md @@ -1,17 +1,17 @@ # Invariants the setup must not break The harness rests on nine invariants (listed below, each with its setup-time -implication). harness-init must not generate anything that violates them — this +implication). env-init must not generate anything that violates them — this is what *you*, running this skill, must be careful about. | # | Invariant | What it means at setup time | |---|-----------|------------------------------| -| 1 | **State lives on disk + branches** | Never generate a daemon, a background queue, or a config that caches "current work" in memory. Counters go in `.harness/` files; sentinels are committed. | +| 1 | **State lives on disk + branches** | Never generate a daemon, a background queue, or a config that caches "current work" in memory. Retry counters go in the harness repo's `state//`; sentinels are committed to the feature branch. | | 2 | **Branch namespace IS the registry** | The claim is the atomic rename `prd//` → `feature/`. Do not add a `.claimed` marker or a lock service. A `feature/` is harness-owned **iff** `prds//prd.md` is committed to it. | -| 3 | **Worktree ↔ branch is 1:1** | Each feature gets its own worktree path `${WORKTREE_BASE}-${feature}`. Never generate logic that switches one worktree between branches. | +| 3 | **Worktree ↔ branch is 1:1** | Each feature gets its own sibling worktree `-harness-`. Never generate logic that switches one worktree between branches. | | 4 | **Skill idempotency (write-then-touch)** | Sentinels are written *after* artifacts are committed. The dispatcher checks only the sentinel. Don't add completion checks based on partial artifact presence. | -| 5 | **Dispatcher discipline** | Zero LLM calls in the dispatcher. One step per branch per tick. `claude -p` invocations are synchronous, never backgrounded with `&`. `flock -n` serializes ticks. The build loop and the memory loop (`learn-tick.sh`) are two independent loops, each `flock`-serialized on its own script and operating on its own worktree, so neither blocks the other; they coordinate only through git (the `refs/harness/last-learned` watermark + `ls-remote` idempotency on `learn/`). | -| 6 | **Human's working tree is sandboxed** | THE TRUST INVARIANT. The harness dispatch never runs in the human's checkout. harness-init may write/commit setup files there (the human is present and consenting), but the running harness operates only in `*-harness*` worktrees. `bootstrap-worktree.sh` copies secrets FROM the human checkout INTO worktrees — never the reverse, never deletes. | +| 5 | **Dispatcher discipline** | Zero LLM calls in the dispatcher. One step per branch per tick. `claude -p` invocations are synchronous, never backgrounded with `&`. Ticks serialize per environment on `state//tick.lock` (`flock -n`), and the exit code is the whole scheduling protocol (0 idle / 10 advanced / else error). The build loop and the memory loop (`learn-dispatch.sh`) are two independent loops with separate locks and separate worktrees, so neither blocks the other; they coordinate only through git (the `refs/harness/last-learned` watermark + `ls-remote` idempotency on `learn/`). | +| 6 | **The developer's working tree is sandboxed** | THE TRUST INVARIANT. The harness operates on the environment only through its *refs* (`git -C fetch/push`) and through *sibling worktrees* — it never touches the developer's checked-out files. env-init may write/commit setup files in the checkout (the developer is present and consenting), but the running harness never does. `bootstrap-worktree.sh` copies secrets FROM the developer's checkout INTO worktrees — never the reverse, never deletes. | | 7 | **Cross-node safety** | Safety comes from atomic git ref ops + `ls-remote` idempotency checks, not coordination services. Keep those primitives even when N=1 — they cost nothing and are the upgrade path. | | 8 | **Verification is non-bypassable** | The dispatcher cannot vouch for "done"; only `run-prd-test.sh` exit 0 + CI gates can. Never generate a path that opens/merges a PR without the runner passing. `local-checks.sh` is an *additional* gate, not a replacement. Caching the first green run in `specs//.prd-passed` is **not** a bypass — the runner still ran and passed; don't "optimize" by skipping the run before the sentinel exists. | | 9 | **Forward-only state machine** | Skills walk forward; none un-touches another's sentinel. Recovery from a wrong plan is human-triggered (delete branch, refile PRD), never a dispatcher rewind. Don't generate "go back a step" logic. | @@ -20,15 +20,16 @@ is what *you*, running this skill, must be careful about. **Invariant 6.** If a developer ever fears the harness will stomp their uncommitted work, the whole design loses their trust regardless of how clean it -is. When the skill explains anything that writes to disk, be explicit about -*where* it writes and confirm that the human's main checkout is never the -dispatch surface. The secret-copying step in `bootstrap-worktree.sh` is the one -place the skill touches sensitive files — flag it loudly and get explicit -consent. +is. The two-tier split makes this structural — the dispatcher lives in the +harness repo and only ever runs `git -C ` ref operations plus sibling +worktrees — but what you *generate* must uphold it too. When the skill explains +anything that writes to disk, be explicit about *where* it writes. The +secret-copying step in `bootstrap-worktree.sh` is the one place the skill +touches sensitive files — flag it loudly and get explicit consent. ## Mode independence -These invariants hold for local laptop, server, and CI alike. harness-init sets -up the *local* mode today, but must not generate anything that would have to be +These invariants hold for local laptop, server, and CI alike. env-init sets up +the *local* mode today, but must not generate anything that would have to be torn out to move to server/SDK mode later. Concretely: keep the cross-node primitives, keep state on disk, keep the dispatcher LLM-free. diff --git a/skills/harness/harness-init/references/local-checks-design.md b/skills/harness/env-init/references/local-checks-design.md similarity index 100% rename from skills/harness/harness-init/references/local-checks-design.md rename to skills/harness/env-init/references/local-checks-design.md diff --git a/skills/harness/env-init/references/mental-model.md b/skills/harness/env-init/references/mental-model.md new file mode 100644 index 0000000..40abacb --- /dev/null +++ b/skills/harness/env-init/references/mental-model.md @@ -0,0 +1,142 @@ +# Mental model — what the harness is + +Read this first. It is the condensed version of the design, written so the +skill can explain the harness to a developer who has never seen it. When you +walk a user through setup, narrate from this. + +## One sentence + +The harness is a system of deterministic code driving probabilistic code: a +polling loop watches a git branch namespace and, for each feature in flight, +runs exactly one spec-driven step per tick in an isolated worktree — until the +system emits its one well-defined output, **a PR that is either ready to merge +or STUCK with a diagnosis**. + +## Two tiers + +``` +HARNESS REPO (tier 1) one repo, N environments. Project-agnostic: + bin/context-specs the CLI (registry, symlinks, supervisor) + scripts/poll-and-dispatch.sh the build-loop dispatcher + scripts/learn-dispatch.sh the memory-loop dispatcher + skills/ the canonical skills (symlinked into envs) + state// per-env runtime state (counters, locks, logs) + +ENVIRONMENT REPO (tier 2) each project. Project-specific (Software 3.0): + AGENTS.md the eager contract + .claude/skills/intent/ project-owned /intent (committed) + .claude/skills/expert/ the Expert — long-term memory (committed) + scripts/bootstrap-worktree.sh makes fresh worktrees runnable (+ re-links skills) + scripts/local-checks.sh the deterministic pre-PR gate + .harness/env this env's dials on the dispatcher (committed) + .claude/skills/ gitignored SYMLINKS into the harness repo +``` + +The tier test: *could you write it without reading the project's code?* +Yes → harness repo (improve it once, every environment benefits). +No → environment (generated by /env-init, evolves with the project). + +## Three layers, independent + +``` +SUPERVISOR context-specs start — one background process per environment. + | Owns TIMING only. Exit 10 from a tick = work advanced → + | re-invoke immediately (drain); 0 = idle → sleep the interval. + v +DISPATCHER scripts/poll-and-dispatch.sh . Pure bash, zero LLM + | calls. Owns ROUTING: reads refs + disk, decides the next skill + v per branch, shells out. The if/elif chain IS the state machine. +INNER LOOP one fresh `claude -p "/skill ..."` subprocess per step. + Owns THE WORK. Fresh context every time, exits when done. +``` + +You can swap any layer without touching the others. This stack is the **build +loop** (features). The **memory loop** has the same shape — supervisor → +`scripts/learn-dispatch.sh` → one `claude -p "/learn …"` in the dedicated +`-harness-learn` worktree — and runs post-merge memory updates without ever +blocking (or being blocked by) the build loop; the two coordinate only through +git (the `refs/harness/last-learned` watermark ref). + +## The worktree topology + +``` +/ the developer's clone. The harness touches only its + REFS (fetch/push) and hangs sibling worktrees off it — + never its working tree. (Inv 6) +-harness-/ EPHEMERAL per-feature worktree. One per in-flight + feature; the dispatcher creates it (off feature/) + and tears it down on merge/close. (Inv 3) +-harness-learn/ the memory loop's dedicated worktree. Persistent + + reused; reset to a clean learn/ off main each run. +``` + +There is no third "host" checkout: the dispatcher lives in the harness repo, so +nothing needs a place to run *inside* the environment. `WORKTREE_BASE` derives +from the environment's path, so per-feature paths are always +`-harness-` siblings. + +## Why the split matters for setup + +- **The dispatcher is deterministic.** No model in the decision path. This is + what makes crash recovery free and behavior predictable from disk state. +- **Every step runs in a fresh context window.** The supervisor and dispatcher + never do real work; each skill runs in its own `claude -p` subprocess, so no + step inherits another's polluted window. +- **The install itself follows the same split**: `context-specs add` did the + deterministic part; /env-init (you) does the part that requires reading the + project. + +## The state machine in one table + +| Branch state | Means | Next action the dispatcher takes | +|------------------------|--------------------|-----------------------------------------| +| `prd//` | waiting in queue | atomic-rename to `feature/` (claim) | +| `feature/` no specs | claimed, unplanned | `/spec-planning` | +| `.planning-done` | planned | `/spec-validate` | +| `.validated` | validated | `/implement-mainspec` until runner == 0 | +| runner exits 0 | implemented | open PR against `main` | +| PR has findings | in review | `/address-feedback` (bounded) | +| PR merged | done | cleanup worktree (the memory loop runs `/learn` separately) | + +"Done" is one thing only: `./prds//run-prd-test.sh` exits 0. The harness +contracts on that exit code and nothing else — that is the **goal** the loop +pursues until it's met or the retry cap turns it into STUCK. + +## The artifacts ARE the state + +There is no database, no in-memory queue, no "what step are we on" file. A +sentinel file existing IS that phase being done. The branch namespace IS the +work registry. Retry counters live in the harness repo's `state//`. +Everything the dispatcher needs is re-derivable from `git` + the filesystem on +every tick. That is the whole recovery story: `kill -9` mid-step leaves nothing +the next tick can't sort out. + +## Memory: long-term informs short-term + +The Expert (+ AGENTS.md) is the project's **long-term memory**; the mainspec + +slices `/spec-planning` writes are **short-term memory** — the plan for one +feature, informed by the long-term memory every time. Improve a shard of +long-term memory and every future feature plans better. Three write paths: +`/learn` after each merge (off the hot path), the implementer's Reflect step +after each slice (on the hot path), and **the developer directly** — the Expert +is developer-owned; the loops are helpers. + +## Where the human steers + +Exactly three points: +1. **Confirming a PRD** (via the project-owned `/intent`, in their own checkout). +2. **Merging a PR** (the feature PR after `/evaluate-pr`, and the `learn/` + memory PR). +3. **Unsticking a STUCK** (diagnosis-first: fix the context, then the code). + +Everything between is the harness. The loop never merges — that is the steering +input the system is built around. + +## What env-init is actually standing up + +The environment's half of the contract: its config dial (`.harness/env`), its +eager contract (`AGENTS.md`), its two owned levers (`/intent`, the Expert), its +provisioning (`bootstrap-worktree.sh`), its deterministic gate +(`local-checks.sh`), and its reviewer. The loops, the dispatcher, and the +canonical skills all live in the harness repo — `context-specs add` already +wired them. diff --git a/skills/harness/harness-init/references/project-discovery.md b/skills/harness/env-init/references/project-discovery.md similarity index 98% rename from skills/harness/harness-init/references/project-discovery.md rename to skills/harness/env-init/references/project-discovery.md index 1449382..825f1ce 100644 --- a/skills/harness/harness-init/references/project-discovery.md +++ b/skills/harness/env-init/references/project-discovery.md @@ -1,6 +1,6 @@ # Project discovery — how to read a codebase before generating -Three artifacts harness-init generates are codebase-dependent and must NOT be +Three artifacts env-init generates are codebase-dependent and must NOT be hardcoded: `AGENTS.md`, `scripts/local-checks.sh`, and `scripts/bootstrap-worktree.sh`. This file is the shared discovery procedure that feeds all three. Run the scan once, then reuse the findings. diff --git a/skills/harness/harness-init/references/reviewer-options.md b/skills/harness/env-init/references/reviewer-options.md similarity index 98% rename from skills/harness/harness-init/references/reviewer-options.md rename to skills/harness/env-init/references/reviewer-options.md index 7a0e652..b8e0140 100644 --- a/skills/harness/harness-init/references/reviewer-options.md +++ b/skills/harness/env-init/references/reviewer-options.md @@ -20,7 +20,7 @@ conversational mode). - **Setup:** drop `assets/workflows/claude-review.yml` into `.github/workflows/`, drop `REVIEW.md` at repo root, add the auth secret (next bullet), and **pin** - the action: replace `@v1` with the current release tag (harness-init looks up + the action: replace `@v1` with the current release tag (env-init looks up and pins the latest at setup time). - **Auth — two options, pick one:** - **`CLAUDE_CODE_OAUTH_TOKEN`** — uses a Claude **Max/Pro subscription** diff --git a/skills/harness/env-init/references/worktree-bootstrap.md b/skills/harness/env-init/references/worktree-bootstrap.md new file mode 100644 index 0000000..ecea36b --- /dev/null +++ b/skills/harness/env-init/references/worktree-bootstrap.md @@ -0,0 +1,98 @@ +# Worktree bootstrap — making a fresh worktree runnable + +`scripts/bootstrap-worktree.sh` (environment-owned) provisions a newly created +git worktree so the project can actually run inside it. Generate it from +`assets/bootstrap-worktree.template.sh`: the template's **deterministic header +is verbatim** — only the section below the marker is Software 3.0, generated by +reading the project (see project-discovery.md), explained to the user, and +confirmed before it's written. + +## Why it exists + +`git worktree add` gives you a checkout of tracked files only. Everything +gitignored — `node_modules`, `target`, `.venv`, `.env`, generated code, **and +the tier-1 skill symlinks** — does NOT come along. So a fresh worktree is like +a new developer's laptop on day one: the code is there, but it won't run until +someone installs deps, drops in secrets, runs codegen — and re-links the +skills, or every headless `claude -p` step runs skill-less. + +## The deterministic header (do not modify) + +```bash +"${CONTEXT_SPECS_HOME:?...}/bin/context-specs" link "$WT" +``` + +Re-creates the skill/agent symlinks in the new worktree. `CONTEXT_SPECS_HOME` +is exported by the dispatcher (which derives it from its own location), so +nothing machine-specific is committed; a human running the script by hand +exports it to their harness repo path. `link` is idempotent and fast — safe on +every invocation. + +## Callers + +1. **The dispatcher**, after every `git worktree add` (per-feature worktrees). +2. **The memory loop** (`learn-dispatch.sh`), when it first creates the + persistent `-harness-learn` worktree. + +So the script must be **idempotent** and **non-interactive** — it runs +unattended inside the loop. + +## Contract + +``` +scripts/bootstrap-worktree.sh +``` + +- Takes the target worktree path as its one argument. +- Determines the **source checkout** (the developer's clone, where the real + gitignored files live) via `git -C rev-parse --git-common-dir` + → its parent is the main worktree. Use that as the copy source. +- Exits 0 on success, non-zero with a clear message on failure. +- Re-running on an already-provisioned worktree is a cheap no-op. + +## What the generated section typically does, in order + +1. **Copy gitignored runtime files** from the source checkout: `.env`, + `.env.local`, local credentials, certs — whatever `.env.example` and + `.gitignore` reveal the project needs. Copy only files that exist in the + source; never fail because an optional one is absent. +2. **Install dependencies** using the project's package manager and lockfile + (`npm ci`, `pnpm i --frozen-lockfile`, `uv sync`, `cargo fetch`, ...). +3. **Run codegen** if the project needs it before it runs (`prisma generate`, + protobuf/GraphQL codegen, migrations against a local/test DB, ...). +4. **Any project-specific "make it runnable" step** the README/CI revealed. + +## The secret-copying caution — flag this loudly + +Step 1 copies REAL secrets from the developer's clone into the sibling +worktree. This is the one place the harness touches sensitive files. When you +present this step: + +- Say explicitly what files will be copied and from where. +- Confirm the destination is a `*-harness*` worktree on the same machine, owned + by the same user — secrets don't leave the box. +- Copy direction is **always** source-checkout → worktree. Never the reverse. + Never delete from the source. (Invariant 6.) +- If the project has no gitignored secrets, skip step 1 entirely and say so. +- Get explicit consent before writing a script that copies secrets. + +## Things to get right + +- **Idempotency.** It runs on every `git worktree add`. Guard expensive steps + (`[[ -d node_modules ]] && lockfile unchanged → skip install`). +- **Non-interactive.** No prompts; it runs in the loop. Use `--frozen`/`ci` + install flavors that don't prompt. +- **Port awareness.** If codegen or a setup step starts a server, it can collide + with the developer's dev server. Prefer steps that don't bind ports; if + unavoidable, read the port from env (note this in the script's comments). +- **Fail loudly, not silently.** A worktree that's missing deps should make + bootstrap exit non-zero with a clear message — otherwise the failure surfaces + later as a confusing PRD-runner failure. +- **Comment the script.** The human owns it. Every step gets a one-line comment. + +## If discovery comes up empty + +If you cannot determine how the project installs/runs (no manifest, sparse +README, no CI), do not guess. Ask the user directly: "How do you set up this +project on a fresh machine? What do you install, and what secret/config files +do you copy in?" Their answer becomes the generated section. diff --git a/skills/harness/fix-local-checks/SKILL.md b/skills/harness/fix-local-checks/SKILL.md index 80c8ec6..4ead74c 100644 --- a/skills/harness/fix-local-checks/SKILL.md +++ b/skills/harness/fix-local-checks/SKILL.md @@ -88,7 +88,7 @@ decision. The ability to skip is the human's, never yours. feature worktree (the dispatcher `cd`s into it; there is no print-mode `--cwd` flag), after the auto-fix pass left the gate red. - **You do NOT track rounds.** The dispatcher owns the counter - (`.harness/local-check-attempts-`) and decides when to STUCK. You do one focused + (`/state//local-check-attempts-`) and decides when to STUCK. You do one focused pass per invocation. - **Completion:** your commit + push. The dispatcher re-runs `local-checks.sh` next tick; if green it moves to PR, if red it re-invokes you (or STUCKs at cap). diff --git a/skills/harness/harness-init/SKILL.md b/skills/harness/harness-init/SKILL.md deleted file mode 100644 index 0c16241..0000000 --- a/skills/harness/harness-init/SKILL.md +++ /dev/null @@ -1,377 +0,0 @@ ---- -name: harness-init -description: One-time setup of the local agent-first coding harness — the polling loop, the deterministic dispatcher, its config, the AGENTS.md contract, and the worktree provisioning that makes per-feature worktrees runnable. Runs as an autonomous installer: writes the artifacts, then opens a feature/harness-init PR for the human to review and merge. Use when a developer wants to set up, bootstrap, install, or initialize the coding harness for the first time in a project. ---- - -# harness-init - -Stand up the **local** coding harness for a project. You are an autonomous -installer: you write the artifacts end-to-end, explain the *significance* of each -as you go, and gather everything onto a `feature/harness-init` PR the human -reviews and merges. The developer should finish understanding what the harness -*is* and why each piece exists — not because you paused for approval at every -line, but because the narration and the PR together make it legible. - -> Scope: this sets up the **local** harness (Claude Code `/loop` outer runtime). -> Server / Claude Agent SDK / OpenSWE modes are future iterations — the -> artifacts here are built so they don't have to be torn out to move there. - -## Operating mode - -Run Steps 0–8 end-to-end without stopping for per-step approval. Do not ask the -user to confirm each file write or present diffs for sign-off — **the user -reviews everything in the `feature/harness-init` PR (Step 8).** Your job while -installing is to explain *significance*: for each artifact, say in a sentence or -two what it is, why it exists, and what would break without it. Lead with the -why, then write the file. - -Read first, before you start writing: -- `references/mental-model.md` — so you can explain what the harness *is*. -- `references/invariants-to-preserve.md` — the rules nothing you generate may break. - -Then load other references as each step needs them. - -Two kinds of artifact: -- **Canonical** (drop in verbatim from `assets/`): the dispatcher, the shim - skills, `REVIEW.md`, the env template, the AGENTS.md template skeleton, the - review workflow. Same everywhere — install and explain, don't reinvent. -- **Software 3.0** (generated by reading the repo): `AGENTS.md`'s filled-in - parts, `scripts/local-checks.sh`, and `scripts/bootstrap-worktree.sh`. Scan, - generate, cite the evidence. **Never invent a command you didn't see - evidence for** — ask instead. - -**Stop-and-confirm points — the only times you interrupt the autonomous install:** - -1. **Step 6 secret-copying** — before writing any `cp` line that touches a - `.env` or credentials file, name the exact files, confirm copy direction - (source → worktree, never reverse, never delete), and get explicit consent. -2. **Step 7 reviewer choice** — recommend the self-hosted default, but confirm - which reviewer path (and, for self-hosted, which auth) the user wants *before* - configuring it. This wires CI and billing, so it's the user's call. -3. **Step 8 the PR merge** — after the PR opens, you stop and wait for the human - to merge before the host worktree and loops can start. - -Everything else runs without interruption. A non-blocking `[warn]` (e.g. an -existing artifact) is noted and handled (re-run mode), not a stop. - -## Preconditions - -The skill runs in the **human's checkout** (their normal working copy), on -`main`, with a clean tree and an `origin` remote. The harness will operate in -sibling worktrees, never here (Invariant 6) — but setup writes happen here -because the human is present, and they land on `main` only via the Step 8 PR. - ---- - -## The install chain - -### Step 0 — Preflight - -Run `scripts/preflight.sh` from the repo root and interpret the report: - -- `[MISS]` on environment (no git repo, no `gh`) → resolve before continuing. -- `[MISS]` on inner skills → see "Inner skill dependency" below; note them, don't - block. -- `[warn]` on existing artifacts → this is a re-run; diff against what's there - rather than clobbering. - -Summarize what you found in plain language and continue. - -### Step 1 — Config (`.harness/env`) - -Read `references/config-options.md`. Derive the author-slug from -`git config user.email`. `MAX_WORKTREES` (default 1) and `WATCH_PATTERN` -(per-dev default) carry tradeoffs — use the defaults unless there's a concrete -reason not to. Write `.harness/env` from `assets/harness-env.template` with the -chosen values. Add the runtime counter files to `.gitignore`: - -``` -.harness/feedback-rounds-* -.harness/local-check-attempts-* -.harness/implement-attempts-* -.harness/planning-attempts-* -.harness/validate-attempts-* -.harness/stuck-* -.harness/human-review-* -.harness/sessions-*.tsv -.harness/learn-review-body-* -``` - -(The memory loop keeps no local watermark file — the `refs/harness/last-learned` -ref on the remote is the watermark — so there is no `last-main-sha` to ignore.) - -`.harness/env` itself is committed; only the counters are ignored. - -### Step 2 — The dispatcher, the shared lib, and the two tick wrappers - -Read `references/dispatcher-explained.md`. Copy these from `assets/` into `scripts/` -and `chmod +x` the shell scripts: - -- `poll-and-dispatch.sh` — the build-loop dispatcher (features). -- `harness-tick.sh` — the build-loop wrapper. -- `harness-lib.sh` — shared helpers (`run_claude`, `render_sessions_table`, - `worktree_for`, `bootstrap_worktree`), sourced by both loops. **No `chmod +x`** — - it's sourced, never executed. -- `learn-tick.sh` — the **memory-loop** wrapper (the post-merge `/learn` driver). - -Explain the load-bearing properties as you install them — the dispatcher's -HUMAN_REVIEW convergence exit (the reviewer's `REVIEW_CLEAN_MARKER` comment hands -the PR to the human for `/evaluate-pr`), the **bootstrap hook** (the project-owned -worktree provisioning), and the **`harness-tick.sh` wrapper**: the build loop -targets the wrapper, which force-syncs the host worktree to a clean `origin/main` -and *then* `exec`s the (HEAD-agnostic) dispatcher. The sync lives in the wrapper, -not the dispatcher, because the dispatcher must never reset its own running file — -and this is how loop-infrastructure updates merged to main (dispatcher, -`.harness/env`) reach the loop; feature *pipeline* skills ride the PRD branch and -need no sync. - -Then explain **the memory loop is a separate loop** (`references/dispatcher-explained.md` -→ "The memory loop"): `/learn` is NOT a dispatcher step. `learn-tick.sh` runs it under -its own `/loop … /learn-loop`, in its own dedicated `../-harness-learn` worktree, -gated by the `refs/harness/last-learned` watermark ref and paused while a `learn/` -PR is open. The two loops never block each other and coordinate only through git. - -### Step 3 — The shim skills - -Copy **both** shims: `assets/poll-and-dispatch-SKILL.md` → -`.claude/skills/poll-and-dispatch/SKILL.md` and `assets/learn-loop-SKILL.md` → -`.claude/skills/learn-loop/SKILL.md`. The significance: an outer `/loop` session -must never do real work — each shim only calls its tick script (`harness-tick.sh` -/ `learn-tick.sh`), and all real work happens in fresh `claude -p` subprocesses, -so no step inherits another's polluted window. - -### Step 4 — `AGENTS.md` (Software 3.0) - -Read `references/agents-md-guidance.md` and `references/project-discovery.md`. -Scan the repo, fill `assets/AGENTS.md.template`'s bracketed parts (project name, -the verification-layer tooling), keep the rest verbatim. AGENTS.md is the neutral, -eagerly-loaded contract — a map that points into the Expert, not an encyclopedia; -keep it tight (the freshness lint caps the root at ~150 lines). Cite the scan -finding behind each filled-in line as you write it. The Expert section is -intentional even though the Expert is empty until the first `/learn`. - -### Step 5 — `scripts/local-checks.sh` (optional, Software 3.0) - -The deterministic gate the dispatcher runs before opening a PR (two-strike retry: -`local-checks.sh fix` → `/fix-local-checks` → STUCK). It's the cheapest place to -catch correctness issues — left of the reviewer and CI. **Read -`references/local-checks-design.md` first** and narrate the *why*; the user owns -and tunes this script. Detect commands via `references/project-discovery.md`. - -It has two responsibilities (the reference details both): - -- **Wire the project's deterministic checks** — lint/format (with a `fix` - subcommand), typecheck, the **fast** unit suite (slow/integration → CI), a - **skip-detection** check, and everything in `scripts/lints/`. Prefer commands the - project already defines; call existing pre-commit hooks rather than duplicating. -- **Propose custom correctness lints** from the codebase as-is (snapshot discovery) - — observed existing invariants + surface-scoped best-practice lints, behind the - five guards in the reference. - -The gate proves **correctness, not coverage** — block only correctness/structural, -*warn* on legibility/observability, and don't add checks for volume (mutation -testing is a sensor, not here). The **skip rule** is load-bearing: an agent may -never add a test-skip marker; a legitimate skip is the human's call at STUCK. - -If the project clearly has no deterministic checks to wire, skip this — the -dispatcher treats the script as absent and works fine. **If you do generate it,** -mind the Step 6 dependency: because it runs typecheck and tests, the worktree must -be fully runnable, so `bootstrap-worktree.sh` has to be solid or these legs fail -for the wrong reason. - -### Step 6 — `scripts/bootstrap-worktree.sh` (Software 3.0) - -Read `references/worktree-bootstrap.md`. This makes a fresh worktree runnable: -copy gitignored runtime files (`.env`, secrets) from the human's checkout, -install dependencies, run codegen. Discover the setup from README/CI/manifests -(project-discovery.md); if discovery is thin, **ask the user how they set the -project up on a fresh machine**. - -**Flag the secret-copying loudly — stop-and-confirm point 1.** This is the one place the -harness touches sensitive files: name exactly which files get copied and from -where, confirm the destination is a same-machine `*-harness*` worktree, confirm -copy direction is always source→worktree and nothing is deleted, and get explicit -consent before writing those lines. If the project has no gitignored secrets, skip -that part and say so. Generate an idempotent, non-interactive, well-commented -script. - -### Step 7 — Reviewer (stop-and-confirm point 2) - -Read `references/reviewer-options.md`. There are three paths (self-hosted via -`claude-code-action` = recommended default; managed Code Review; none); switching -later is cheap (one workflow file). **This step is not autonomous: present the -three paths, recommend self-hosted, and confirm with the user which path they -want — and, for self-hosted, which auth — before configuring anything.** It wires -CI workflow files and a billing choice, so it's the user's decision. Once they -choose, install that path: -- **Self-hosted:** copy `assets/REVIEW.md` to repo root + `assets/workflows/claude-review.yml` - to `.github/workflows/`, and: - 1. **Pick auth with the user.** The template ships with `claude_code_oauth_token` - active and `anthropic_api_key` commented. Ask which they want: - **subscription** (`CLAUDE_CODE_OAUTH_TOKEN` from `claude setup-token` — uses - their Max/Pro plan, shares its usage limits) vs **metered API** - (`ANTHROPIC_API_KEY` from console.anthropic.com — separate billing, better for - teams/CI). Uncomment the chosen line, comment the other, and have them add the - matching repo secret. (Max and the API are separate billing products.) - 2. **Pin the action.** Look up the current `anthropics/claude-code-action` - release (e.g. `gh release view --repo anthropics/claude-code-action`) and - replace `@v1` with that tag (e.g. `@v1.2.3`). - 3. **Tell them the v1 same-content rule:** the workflow must be byte-identical on - the PR branch and the default branch, so it only takes effect once merged to - `main` and can't be tested from a feature branch. - Note the template is the v1 API (`prompt` + `track_progress` + `claude_args` + - `id-token: write`); it does NOT use the pre-v1 `mode`/`review_instructions_path` - inputs. The reviewer is PR-triggered and one-way; if the user also wants an - interactive `@claude` agent, that's the stock `examples/claude.yml` added - separately (see reviewer-options.md) — not bundled here. -- **Managed:** copy `REVIEW.md`; give the GitHub App install instructions. -- **None:** create nothing; set `REVIEW_CLEAN_MARKER=` (empty) in `.harness/env` so - the dispatcher converges at PR-open and hands straight to `/evaluate-pr`; note a - reviewer is addable later. - -**Convergence marker (both reviewer paths).** `REVIEW.md` instructs the reviewer to -post a PR comment containing `HARNESS_REVIEW_CLEAN` once it has no Important findings -left. That marker is how the dispatcher knows the review loop converged and hands the -PR to the human for `/evaluate-pr` — a single deterministic signal, the same for -managed and self-hosted. The token is configurable via `REVIEW_CLEAN_MARKER` in -`.harness/env` (must match what `REVIEW.md` tells the reviewer to post). If the -reviewer never posts it, the feedback loop reaches `FEEDBACK_CAP` and STUCKs -instead — a clean PR the human merges. - -### Step 8 — Commit on `feature/harness-init`, push, open PR, wait for merge - -**Hard rule: never commit harness setup artifacts directly to `main`.** Everything -from Steps 1–7 lands on `feature/harness-init` and reaches `main` only via a merged -PR. This is the review checkpoint — the whole install in one diff. - -Create the branch, stage the artifacts, commit, push, and open the PR: - -``` -git checkout -b feature/harness-init -git add .harness/env .gitignore scripts/ AGENTS.md REVIEW.md .github/ -git commit -m "harness: initial setup via harness-init" -git push -u origin feature/harness-init -gh pr create --base main --head feature/harness-init \ - --title "harness: initial setup" --fill -``` - -Walk the user through the PR — what's in it, why each piece is there — then **stop -and ask them to merge it before continuing (stop-and-confirm point 3).** - -**Why merge first?** Two load-bearing reasons: -- Step 9 creates the host worktree with `git worktree add --detach … origin/main`. - Until the merge lands, `origin/main` has none of the harness scripts, so the - worktree would be empty of `harness-tick.sh` and `poll-and-dispatch.sh`. -- `harness-tick.sh` force-resyncs to `origin/main` on every tick. Even if you - bootstrapped from the feature branch directly, the first tick would wipe it back - to a `main` that has no scripts. - -Once the user confirms the PR is merged and their local `main` is current -(`git fetch && git pull`), continue to Step 9. - -### Step 9 — Host worktree + provision - -Explain the three-checkout model (see `references/mental-model.md`): the human's -checkout stays on `main`; the harness **host** worktree is a sibling that stays -**detached at `origin/main`** (re-synced every tick by `harness-tick.sh`); -per-feature work happens in *ephemeral* `../-harness-` worktrees the -dispatcher creates and tears down. Create the host worktree **detached** — git -won't let two worktrees check out `main` at once, and the human's checkout already -holds it: - -``` -git worktree add --detach ../-harness origin/main -``` - -Then provision it with `scripts/bootstrap-worktree.sh ../-harness`. This -**doubles as validation of the bootstrap script** — if the host worktree is -runnable afterward, the script works. Verify runnability before continuing; fix -and re-run if not. - -### Step 10 — Dry-run the tick - -From the **harness host worktree** (`../-harness`), run -`./scripts/harness-tick.sh` once. It force-syncs the worktree to `origin/main` -and then runs the dispatcher; with no PRDs filed it should be a clean no-op -(fetch, sync, find nothing, exit 0). This proves the build-loop wiring — sync -wrapper + dispatcher — without doing any work. - -Then run `./scripts/learn-tick.sh` once. On a fresh repo (Expert not yet built, no -merges since the watermark) it creates and bootstraps the `../-harness-learn` -worktree, finds no new range, and exits — proving the memory-loop wiring. Walk -through both outputs with the user. If anything errors, debug before starting the -loops. - -### Step 11 — Start the loops - -Explain how to start the harness. It runs as **two independent loops**, each in its -own long-lived Claude Code session pinned to the harness worktree — the build loop -(features) and the memory loop (`/learn`). They never block each other: - -``` -cd ../-harness - -# session 1 — the build loop (features): -claude -/loop 5m /poll-and-dispatch - -# session 2 — the memory loop (/learn), in a SEPARATE session: -claude -/loop 10m /learn-loop -``` - -The memory loop can tick lazily (10m is fine) — it only acts when main has advanced -past the `refs/harness/last-learned` watermark and no learn PR is already open. Offer -to start them if they're ready. Finish with the **daily flow** recap: -1. `/intent` in their normal checkout → confirm a PRD → walk away. -2. Harness picks it up, runs the chain, opens a PR. -3. Either: - - **Normal path:** when the reviewer converges, the harness posts a "Ready for - your review" comment with the build-session trail and halts. Run - **`/evaluate-pr `** to walk the change, run it locally, and build a - firm understanding — then merge it (or fix-and-push, or close). Then review and - merge the `/learn` PR that follows (memory updates). - - **STUCK path:** if any step hits its retry cap, the dispatcher posts a STUCK - PR (or comment) with the session log + a diagnosis-first checklist. **Your - first job is the context defect, not the code** — figure out which - `AGENTS.md` / Expert / spec / PRD content misled the agent, correct it on - the branch, *then* fix the code and merge. `/learn` picks up the context - correction at merge. - ---- - -## Inner skill dependency - -The dispatcher calls `/spec-planning`, `/spec-validate`, `/implement-mainspec`, -`/fix-local-checks`, and `/address-feedback`. `/learn` is driven by the **separate -memory loop** (`learn-tick.sh`), not the dispatcher. Two more are **human-invoked**, -not dispatched: `/intent` (front of the chain) and `/evaluate-pr` (the Evaluate phase -— run after the harness posts its "Ready for your review" handoff). harness-init wires -both **outer** loops; it does not author these. Preflight -reports which are installed. If some are missing, set up the harness anyway and -tell the user clearly which skills must be installed from the catalog before the -chain runs end to end — the harness will dispatch to them the moment they exist. -(The project's Expert is born from the first `/learn`, written directly under -`.claude/skills/expert/`.) - -## Re-running - -Safe to re-run. Preflight flags existing artifacts. For canonical files, diff -and offer to update. For generated files (`AGENTS.md`, `local-checks.sh`, -`bootstrap-worktree.sh`), re-scan and show a diff rather than overwriting blind. -Never delete the human's host worktree or secrets on a re-run. If -`feature/harness-init` already exists from a prior run, detect it, diff the -existing branch against the current state, and update that branch rather than -creating a fresh one. - -## Hard rules (from invariants-to-preserve.md) - -- Never run the dispatch loop in the human's checkout (Invariant 6). -- Never put an LLM call in the dispatcher's decision path (Invariant 5). -- Never replace the atomic-rename claim with a marker/lock file (Invariant 2/7). -- Never generate a "go backward" / sentinel-deleting step (Invariant 9). -- `bootstrap-worktree.sh` copies secrets source→worktree only, never deletes, - never the reverse (Invariant 6). -- Never commit harness setup artifacts directly to `main`. All harness-init - artifacts land on `feature/harness-init` and reach `main` only via a merged - PR. The host worktree and the loops cannot start until that merge (Step 8). diff --git a/skills/harness/harness-init/references/config-options.md b/skills/harness/harness-init/references/config-options.md deleted file mode 100644 index cac380a..0000000 --- a/skills/harness/harness-init/references/config-options.md +++ /dev/null @@ -1,142 +0,0 @@ -# Config options — `.harness/env` - -The harness has a small, deliberately tiny config surface. All of it lives in -`.harness/env` (sourced by the dispatcher) or in the `/loop` invocation. When -you walk the user through config, explain each knob's tradeoff and recommend the -default; only change a default if the user has a concrete reason. - -## The knobs - -### `MAX_WORKTREES` (default `1`) - -How many features the harness works in parallel. - -- **`1` (recommended default).** Single worktree, FIFO. One feature at a time. - No disk multiplication, no duplicate `node_modules`/`target`, simplest mental - model. Right for essentially every single-developer project. -- **`2`+.** Bounded parallelism. Each concurrent feature gets its own worktree - (`${WORKTREE_BASE}-${feature}`), so disk and rebuild cost multiply. Flip this - only when you have several independent features queued AND surplus disk/CI. - -In-flight work always continues regardless of this value — it caps *new intake*, -not continuation. Lowering it mid-flight just stops new claims; existing -features finish. - -### `WATCH_PATTERN` (default `prd//*`) - -Which PRD branches this harness claims. `` derives from -`git config user.email` (the part before `@`). - -| Mode | Pattern | Behavior | When | -|------|---------|----------|------| -| **Per-dev (default)** | `prd//*` | Each dev's harness claims only their own PRDs, on their own laptop, their own API quota. | Default. Best attribution, cost, and observability. | -| **Shared pool** | `prd/*/*` | All harnesses race for everything; atomic rename keeps it safe. | A team deliberately sharing a work pool. | - -Note the glob: `*` matches one path component. Per-dev is `prd/alice/*`; shared -is `prd/*/*` (author component + feature component). - -### STUCK caps - -Bounded-retry circuit breakers — every step has one, so the loop can't run away. -At cap, the dispatcher signals STUCK on the PR (opening it as a draft if no PR -exists yet) with the session log + a diagnosis-first checklist for the human, and -halts that feature. - -| Var | Default | Step it bounds | -|---|---|---| -| `PLANNING_CAP` | 2 | `/spec-planning` (skill crashes or never writes sentinel) | -| `VALIDATE_CAP` | 2 | `/spec-validate` (same) | -| `IMPLEMENT_CAP` | 3 | `/implement-mainspec` (PRD runner keeps failing) | -| `LOCAL_CHECKS_CAP` | 2 | `scripts/local-checks.sh` two-strike (auto-fix → focused LLM fix → STUCK) | -| `FEEDBACK_CAP` | 5 | reviewer feedback rounds | - -All env-overridable in `.harness/env`. Raise for hard features; lower to fail -faster. - -### `REVIEW_CLEAN_MARKER` (convergence signal) - -Default `HARNESS_REVIEW_CLEAN`. When the reviewer has no Important findings left, -`REVIEW.md` instructs it to post a PR comment containing this token; the dispatcher -(`reviewer_converged`) sees it and hands the PR to the human for `/evaluate-pr` (it -writes `.harness/human-review-`, posts the build-session trail once, and halts the -feature until the human merges/closes). Detection is intentionally simple — marker -present → converge, no freshness or author check. If the reviewer never posts it, the -feedback loop reaches `FEEDBACK_CAP` and STUCKs instead (a clean PR the human merges). -Set it **empty** in `.harness/env` when there is **no reviewer**, so the dispatcher -converges at PR-open. Must match whatever `REVIEW.md` tells the reviewer to post. - -### Loop intervals (in the `/loop` invocations, not `.harness/env`) - -There are **two** loops, each its own `/loop` session in the harness host worktree: - -- `/loop 5m /poll-and-dispatch` — the **build loop** (features). `5m` is a sane - default. Shorter = more responsive, more API ticks (most are cheap no-ops). -- `/loop 10m /learn-loop` — the **memory loop** (`/learn`). It can tick lazily: it - only acts when `origin/main` has advanced past the `refs/harness/last-learned` - watermark AND no `learn/` PR is already open. Most ticks are cheap no-ops. - -Both are UX knobs, not correctness ones — the loops self-serialize (`flock`) and -re-derive their state every tick, so a missed or slow tick never corrupts anything. - -### The memory loop's watermark (`refs/harness/last-learned`) - -Not a `.harness/env` value — a git **ref** on the remote, the memory loop's only -durable state. It records how far into `main`'s history `/learn` has digested. -`learn-tick.sh` reads it as the `--since` for the next run and advances it (atomic -`--force-with-lease`) after each run. It lives in its own ref namespace, so it -survives `learn/` branch deletion and is shared across nodes — there is **no** -local `last-main-sha` file anymore. To force a full re-learn, delete the ref -(`git push origin :refs/harness/last-learned`) or run `/learn --rebuild` by hand. - -### `WORKTREE_BASE` (rarely set) - -Where per-feature worktrees are created: `${WORKTREE_BASE}-${feature}`. The -dispatcher derives the default from the **main worktree** name — `../-harness` -— so per-feature paths come out `../-harness-` regardless of which -worktree the dispatcher runs from. Override in `.harness/env` only if you want them -somewhere else (e.g. a different disk). Leave unset otherwise. - -## What does NOT go in config - -- **The claim mechanism** — it's the atomic rename, hardcoded. Not configurable. -- **Completion signals** — sentinel files, hardcoded in the dispatcher. -- **The pipeline order** — that's the `if/elif` chain in the script, edited - directly (see dispatcher-explained.md), not a config value. -- **The host-worktree sync** — done by `scripts/harness-tick.sh` (the `/loop` - target), not a config value. The loop must target the wrapper, not the dispatcher. - -## The `.harness/` directory - -Holds runtime state, all re-derivable, none of it secret: -- `env` — the config above (committed, or kept local — see below). -- `planning-attempts-`, `validate-attempts-`, `implement-attempts-`, - `local-check-attempts-`, `feedback-rounds-` — per-feature retry counters - (each gates a STUCK circuit breaker). -- `stuck-` (sentinel), `stuck-output-.log` (tee'd failing output), - `stuck-body-.md` (the PR-body composed at STUCK) — written when a cap hits; - cleared on merge/close. -- `human-review-` (sentinel — reviewer converged, PR handed to the human), - `human-review-posted-` (marks the trail comment already posted, so it posts - once), `human-review-body-.md` (the "Ready for your review" comment) — written - at convergence; cleared on merge/close. -- `sessions-.tsv` — every `claude -p` invocation for this feature, one row each - (timestamp, step, attempt, session_id, exit, duration). The STUCK PR body - quotes the tail of this file so the human can open the trace by session_id. - -**Counters and session logs must be gitignored.** They are per-node runtime state, -not project artifacts. harness-init adds `.harness/feedback-rounds-*`, -`.harness/local-check-attempts-*`, `.harness/implement-attempts-*`, -`.harness/planning-attempts-*`, `.harness/validate-attempts-*`, -`.harness/stuck-*`, `.harness/human-review-*`, `.harness/sessions-*.tsv`, and -`.harness/learn-review-body-*` to `.gitignore` (the memory loop's watermark is the -`refs/harness/last-learned` ref, not a file). Whether `.harness/env` is committed is a choice: commit it to -share defaults across a team's checkouts; keep it local (gitignored) if each -dev tunes their own. Recommend committing `env` and ignoring the counters. - -## Multi-developer reminder - -Per-dev is the default for a reason (attribution, cost isolation, "my harness is -my assistant" mental model). Don't steer a user to shared-pool unless they -explicitly describe a shared-queue workflow. When a team truly outgrows local -harnesses, the move is to transition to a server/CI harness — not to run many -local harnesses in shared-pool mode forever. diff --git a/skills/harness/harness-init/references/dispatcher-explained.md b/skills/harness/harness-init/references/dispatcher-explained.md deleted file mode 100644 index e7149ea..0000000 --- a/skills/harness/harness-init/references/dispatcher-explained.md +++ /dev/null @@ -1,270 +0,0 @@ -# The dispatcher, explained - -When you drop `assets/poll-and-dispatch.sh` into the project, walk the user -through it using this file. The goal: the user understands every section well -enough to decide whether to tweak it. Never present it as a black box. - -## What it is - -`scripts/poll-and-dispatch.sh` — ~150 lines of bash, `git`, and `gh`. No LLM in -the decision path. It runs once per tick. The `if/elif` chain is the state -machine; the artifacts on disk are the state. - -## The seven load-bearing properties - -Explain these as the "why it's safe" of the script. Each maps to an invariant. - -1. **One transition per tick per branch.** The `if/elif` fires at most one - branch. Next tick, the artifact this tick wrote satisfies the condition and - the *next* `elif` fires. Forward, one step at a time. (Inv 5) -2. **Artifacts are the only state.** A sentinel existing IS that phase being - done. No checkpoint file. Crash recovery is free — next tick re-derives from - disk. (Inv 1 + 4) Most sentinels are written by the skills; `specs//.prd-passed` - is the exception — the *dispatcher* commits+pushes it the first time - `run-prd-test.sh` exits 0, so a runner that shells out to an LLM-as-judge runs - once instead of every tick (and can't non-deterministically re-kick implement). -3. **Wipe + HEAD-check before every advance.** `git reset --hard && git clean - -fd` discards a crashed skill's uncommitted mess; the HEAD guard skips any - worktree whose branch doesn't match the feature being advanced, so a - manually-checked-out branch is never clobbered. Runs only in per-feature - worktrees. (Inv 3 + 6) -4. **Dispatcher never invokes an LLM directly.** It only spawns `claude -p` - subprocesses or shells to `git`/`gh`. Each subprocess is a fresh process and - a clean context window. (Inv 5) -5. **Local checks are optional and bounded.** If `scripts/local-checks.sh` - exists, the PR is gated on it with a two-strike retry (auto-fix, then focused - LLM fix, then stop). No script = gate skipped. (Inv 8) -6. **`MAX_WORKTREES` is the one concurrency knob.** Default 1 = FIFO single - worktree. Claims are lazy: PRDs over capacity stay in `prd//*` as the - visible queue. In-flight work always continues regardless of cap changes. - (Inv 2 + 3) -7. **Convergence has its own exit — HUMAN_REVIEW — separate from STUCK.** The - review loop's healthy end is the reviewer posting `REVIEW_CLEAN_MARKER`; - `reviewer_converged` sees it and writes `human-review-`, the guard posts the - session trail once and halts the feature for the human's `/evaluate-pr`. The - marker (not sticky review state) is the signal, so a clean PR can't false-STUCK - on a stale `COMMENTED` review. If the reviewer never marks clean, the feedback - cap STUCKs instead — fine, the human merges. - -## Section-by-section map - -| Lines (approx) | Section | Tweakable? | -|----------------|---------|------------| -| top | `flock -n` self-lock | No — serializes ticks; load-bearing. | -| config block | `SLUG`, `WATCH`, `WORKTREE_BASE`, `MAX_WORKTREES` | Via `.harness/env`, not by editing here. `WORKTREE_BASE` derives `` from the **main worktree**, not `$PWD` — so per-feature paths are `-harness-` even though the dispatcher runs from the `-harness` host worktree. | -| `has_prd()` | Invariant-2 ownership filter | No — defines what "harness-owned" means. | -| step 1 | re-attach in-flight worktrees | The `bootstrap_worktree` hook call is the local addition (see below). The PR-state **liveness gate** (skip `MERGED`/`CLOSED` features) is load-bearing — don't drop it; see "Liveness" below. | -| step 2 | lazy claim up to capacity | No — atomic rename is the claim lock. | -| step 3 | advance each feature one step | **This is where you add/remove pipeline steps** — one `elif` per step. | -| step 4 | cleanup merged/closed PRs | Safe to extend (e.g., notify on cleanup). | -| post-merge `/learn` | **NOT in this script** — runs in the separate memory loop (`learn-tick.sh`). See "The memory loop" below. | Watermark/idempotency live there. | -| step 3 (review) | the feedback gate has three branches: `reviewer_converged` (marker present) → write `human-review-`; else findings → `/address-feedback`; else cap → STUCK | Convergence is the marker; the gate order matters (converge before the findings loop). | -| helpers (shared) | `run_claude` (session-tagged invocation + TSV log), `render_sessions_table` (shared trail renderer) live in `harness-lib.sh` — both loops use them. | Edit `run_claude` in one place (e.g. the `--session-id` swap). | -| helpers (dispatcher) | `signal_stuck` (PR-body STUCK signal), `signal_human_review` (the convergence handoff comment), `reviewer_converged` (marker check), `has_prd` (ownership filter) | Used by §3 steps that call `claude -p`, hit a cap, or detect convergence. | - -## The bootstrap hook — project-owned worktree provisioning - -A bare worktree has no `node_modules`, no `.env`, no generated code — so slice -signals and the PRD runner fail for reasons unrelated to the feature. So -immediately after every `git worktree add`, the dispatcher runs -`scripts/bootstrap-worktree.sh "$wt"` if that script exists and is executable. -The hook itself is canonical (the design doc's dispatcher includes it); what's -**project-owned** is the `bootstrap-worktree.sh` it calls — harness-init generates -that per project (see `worktree-bootstrap.md`). If the project has no bootstrap -script, the hook is a no-op. - -Make sure the user knows: this hook is why the per-feature worktrees the harness -spins up are actually runnable. - -## Liveness — branch existence is not in-flight (the step-1 PR-state gate) - -`has_prd()` answers *ownership* ("is this a harness feature?"), not *liveness* -("is there still work to do?"). A `feature/` whose PR has **merged** keeps both -its branch (GitHub's delete-on-merge is off by default, and you can't make every -consumer enable it) and its committed PRD — so `has_prd()` stays true forever. -Without a liveness check, step 1 re-attaches that finished feature as in-flight on -*every* tick, which does two bad things at once: - -1. step 3 re-fires `/address-feedback` on the merged PR — wasted tokens, every tick; -2. the phantom occupies a `MAX_WORKTREES` slot, so `capacity` (step 2) drops and a - freshly-filed PRD sits unclaimed in the queue behind a feature that's already done. - -Step 4 cleanup notices the merge and removes the *local* worktree, but it runs -*after* step 3 and doesn't delete the *remote* branch — so the next tick's step 1 -re-attaches the same ghost. The fix is one gate in step 1, right after `has_prd`: -`gh pr view` the feature's PR and `continue` past any `MERGED`/`CLOSED` one. Because -the in-flight set is what feeds the capacity math, that single skip cures both -symptoms. Notes: - -- **No branch deletion.** We never `git push --delete` a merged feature branch — - the harness simply stops treating it as live work. Consumers keep whatever - branch-retention policy they like. -- **Fail-safe on empty state.** A feature still in a pre-PR phase - (planning/validate/implement) has no PR, and a transient `gh` outage also returns - empty — both are kept in-flight so live work is never silently dropped. -- **Forward-only (Inv 9).** Merged is terminal; the gate only ever skips, never rewinds. - -## The tick wrapper — keeping the host worktree current (`harness-tick.sh`) - -The dispatcher is **HEAD-agnostic**: it operates on git *refs* (`origin/feature/*`, -`feature/*`) and per-feature worktrees, never on its own checkout's HEAD. But the -files it executes — the dispatcher itself, `harness-lib.sh`, `bootstrap-worktree.sh`, -`.harness/env` — are read from the **host worktree**, which sits at a detached HEAD -and does not auto-advance when `main` moves. Without a sync step, loop infrastructure -freezes at the commit the host worktree was created on. - -So the build loop targets **`scripts/harness-tick.sh`**, not the dispatcher -directly. The wrapper: - -1. `git fetch origin` -2. `git checkout -f --detach origin/main` + `git clean -fd` — force the host worktree - to a clean, current `main` (idempotent; self-heals whatever state a crash left it in) -3. `exec ./scripts/poll-and-dispatch.sh` - -The sync lives in the wrapper, **before** `exec`, for a reason: if the dispatcher -reset its own checkout mid-run it would overwrite the very file it's executing (and -its `flock` is on `$0`). Doing it in the wrapper means the dispatcher always loads -its freshest version cleanly. The wrapper is tiny and stable; on the rare tick where -it changes on main, that change takes effect the next tick. - -Note the asymmetry: feature **pipeline** skills (`/spec-planning`, `/implement-*`, -`/address-feedback`, …) do **not** need this sync — they run inside per-feature -worktrees that branch from the PRD branch (off main), so new features pick up skill -updates on their own. Only loop-level infra rides the host worktree, and that's -exactly what the wrapper refreshes. - -## The memory loop — `/learn` as its own loop (`learn-tick.sh`) - -`/learn` is **not** a dispatcher step. It runs in a second, independent loop: -`/loop … /learn-loop` → `scripts/learn-tick.sh`. This is the deliberate decoupling -that keeps a multi-minute Expert bootstrap from blocking (or being blocked by) the -build loop. The two loops share a node but never wait on each other — separate -`flock`s on separate scripts — and coordinate only through git (Inv 1 + 7). - -What `learn-tick.sh` does each tick (it is the memory-loop analogue of -`harness-tick.sh` + the old dispatcher step 5): - -1. `flock -n` on itself (self-serialize — a long bootstrap just no-ops later ticks). -2. `git fetch` `main` **and** the watermark ref namespace - (`+refs/harness/*:refs/harness/*`). Fetch only — never the host *working tree*. -3. Ensure the dedicated, **reused** `../-harness-learn` worktree exists (create - + `bootstrap_worktree` on first run — so a drafted lint and `check-agents-md.sh` - can actually run), then reset it to clean `origin/main` (`-fd`, keeping deps). -4. **Pause** if a `learn/` PR is already open (`gh pr list … startswith("learn/")`): - memory edits serialize behind human review. Nothing is queued — the backlog is - implicit in `(watermark, origin/main)` and recomputed every tick. -5. Compute `since = refs/harness/last-learned` (or a bounded look-back on the first - run), `to = origin/main`; if equal, no-op. -6. `git ls-remote origin learn/` idempotency (cross-node first-to-push-wins). -7. Check out `learn/` in the learn worktree and run `/learn --since - --sha ` there. `/learn` writes memory, pushes the branch, opens the PR. -8. `signal_learn_review` posts the session trail on the PR (if one opened). -9. Advance `refs/harness/last-learned` to `` with an atomic CAS - (`--force-with-lease`) — the same first-to-push-wins primitive used to claim PRDs. - -**Why a ref watermark, not the old `.harness/last-main-sha` file.** A ref lives in -its own namespace nothing cleans, so it survives `learn/` branch deletion; it's -on the remote, so it's shared across nodes; and `--force-with-lease` gives a -lock-free compare-and-swap. The file was per-node local state with none of those -properties. The advance happens whether or not `/learn` opened a PR (a 0/3 no-op -merge is still "learned"), matching the old step-5 semantics — only now the anchor is -durable and shared. - -**Why this never races the build loop.** `learn-tick.sh` does all working-tree ops -(`checkout`/`reset`/`clean`) in the `-harness-learn` worktree, never the host -worktree — so the build loop's per-tick host force-sync has nothing of the memory -loop's to wipe. That is what let us delete the old `.harness/learn-running` PID guard -entirely: there is no longer a skill running *in* the host worktree to protect. - -## Human-steering points: Evaluate (HUMAN_REVIEW) and STUCK - -The human steers the machine at three touchpoints (the Human Loop — confirm a PRD, -evaluate-then-merge a PR, unstick a STUCK). Two of those live in this script. - -**HUMAN_REVIEW (the healthy one).** When the reviewer converges (posts -`REVIEW_CLEAN_MARKER`), `reviewer_converged` writes `human-review-`; the guard -posts the build-session trail once and halts the feature. The human runs -`/evaluate-pr` to walk the change, run it, and merge (or fix-and-push, or close). -The loop does not re-engage — the human is the last mile. - -**STUCK (the failure one).** Memory still has **one write path** — `/learn` in the -memory loop, post-merge, ground truth only. There is no separate write path for failed features. -Instead, **STUCK** (a step in §3 hitting its cap) is a first-class escalation: the -dispatcher posts -to the PR (opening it as a draft if needed) with the session log, the failing -output tail, and a diagnosis-first checklist, then halts the feature. The -human's first job at STUCK is to identify the **context defect** (which -`AGENTS.md` / Expert / spec / PRD content misled the agent), correct it on the -branch, *then* fix the code, *then* merge. Those context corrections ride into -main with the merge, where `/learn` picks them up and routes any follow-ups. - -This is why the design no longer has any "Path B" / `lessons.md` machinery — -the human's hands-on diagnosis + correction at STUCK is the learning, and the -merge carries it home. - -## The session log + STUCK signal - -A few small helpers do the legwork. `run_claude` and `render_sessions_table` are -**shared** — they live in `harness-lib.sh`, sourced by both the dispatcher and -`learn-tick.sh`; the rest are dispatcher-local, defined above step 1: - -- **`run_claude ""`** (shared) — wraps every - `claude -p` call. `cd`s into the worktree `` first (there is no print-mode - `--cwd` flag, and the `cd` is what gives the skill its `.claude/` command + - `AGENTS.md` discovery; the build loop passes the per-feature worktree, the memory - loop passes the `-harness-learn` worktree). - Generates a UUID session id, runs `claude -p --session-id "${CLAUDE_PERM_ARGS[@]}"`, - and appends `\t\t\t\t\t` - to `.harness/sessions-.tsv` (gitignored, cleared on merge/close). A - non-zero skill exit is recorded in the row but never aborts the tick (`return 0`). -- **`signal_stuck [output-file]`** — touches the stuck - sentinel, composes a PR body (step, cap, tail of the session log, optional tail - of the failing output, diagnosis-first checklist), and either opens a draft PR - or comments on an existing one. The single human-facing surface for failures. -- **`reviewer_converged `** — true iff a PR comment contains - `REVIEW_CLEAN_MARKER`. One `gh` call, no LLM; deliberately no freshness/author - check (see the helper's comment). Empty marker = no reviewer → false. -- **`signal_human_review `** — the convergence counterpart of - `signal_stuck`: posts the "Ready for your review" comment with the session trail - (via the shared `render_sessions_table`) so the human can `/evaluate-pr`. -- **`signal_learn_review `** — lives in **`learn-tick.sh`**, not the - dispatcher: after `/learn` opens its `learn/` PR, posts the headless session - trail (via the shared `render_sessions_table`) framed for troubleshooting *why* - `/learn` routed each fact as it did, so the human evaluating the memory PR can open - the trace before accepting or revising it. Uses a per-sha session label - (`learn-`) so the table shows exactly that run. - -If your `claude -p` version doesn't support `--session-id`, swap that flag for -`--output-format json` and parse `session_id` from stdout — `run_claude` is the -one place to change. - -## Common tweaks to offer - -- **Add a pipeline step** (e.g. `/security-review` between validate and - implement): insert one `elif` in step 3 with its own sentinel check, its own - `_CAP`, and a `run_claude` / `signal_stuck` pair like the others. -- **STUCK caps** (all built in): `PLANNING_CAP`, `VALIDATE_CAP`, `IMPLEMENT_CAP`, - `LOCAL_CHECKS_CAP`, `FEEDBACK_CAP`. All env-overridable in `.harness/env`. - Raise for hard features, lower to fail fast. -- **Memory-loop cadence** for `/learn`: it lives in `learn-tick.sh`, not here. It - fires whenever `origin/main` advanced past the `refs/harness/last-learned` watermark - and no `learn/` PR is open. A team merging many times per minute can simply run - `/loop` at a longer interval — each run batches every merge since the watermark. - -## What NOT to let the user do - -- Add `&` to any `claude -p` call (breaks synchronous one-step discipline). -- Add an LLM call to the decision logic (breaks Inv 5, makes it non-reproducible - and a cost surface). -- Remove the wipe or the HEAD guard (breaks crash recovery and Inv 6). -- Replace the atomic-rename claim with a marker file (breaks Inv 2 + 7). -- Point `/loop` at `poll-and-dispatch.sh` directly, bypassing `harness-tick.sh` - (loop-infra updates merged to main would never reach the running loop). -- Move the host-worktree sync *into* the dispatcher (it would overwrite its own - running file; the sync belongs in the wrapper, before `exec`). -- Point the memory loop's `/loop` at `poll-and-dispatch.sh`, or fold `/learn` back - into the dispatcher as a step — that re-couples the loops, so a multi-minute Expert - bootstrap again blocks every feature step (the whole reason it's a separate loop). -- Make `learn-tick.sh` do working-tree ops (`checkout`/`reset`/`clean`) in the **host** - worktree instead of `-harness-learn` — it would then race the build loop's - per-tick host force-sync. The memory loop must stay in its own worktree. diff --git a/skills/harness/harness-init/references/mental-model.md b/skills/harness/harness-init/references/mental-model.md deleted file mode 100644 index d266946..0000000 --- a/skills/harness/harness-init/references/mental-model.md +++ /dev/null @@ -1,110 +0,0 @@ -# Mental model — what the harness is - -Read this first. It is the condensed version of the design doc, written so the -skill can explain the harness to a developer who has never seen it. When you -walk a user through setup, narrate from this — do not assume they have read the -design doc. - -## One sentence - -The harness is a polling loop that watches a git branch namespace, and for each -feature in flight, runs exactly one spec-driven-development step per tick in an -isolated worktree, until a PR is open against `main` for a human to merge. - -## Three layers, independent - -``` -OUTER LOOP a long-lived Claude Code session (/loop 5m), or cron, or CI. - | Owns TIMING only. Knows nothing about the work. - v -TICK WRAPPER scripts/harness-tick.sh. Syncs the host worktree to a clean - | origin/main, then execs the dispatcher. Keeps loop infra fresh. - v -DISPATCHER scripts/poll-and-dispatch.sh. Pure bash, zero LLM calls. - | Owns ROUTING: reads disk, decides the next skill per branch, - v shells out. The if/elif chain IS the state machine. -INNER LOOP one fresh `claude -p "/skill ..."` subprocess per step. - Owns THE WORK. Fresh context every time, exits when done. -``` - -You can swap any layer without touching the others. harness-init sets up the -outer loop, the tick wrapper, and the dispatcher; the inner skills come from the -catalog. - -This stack is the **build loop** (features). There is a second, independent loop -with the same shape — the **memory loop**: `/loop … /learn-loop` → -`scripts/learn-tick.sh` → one `claude -p "/learn …"` in the dedicated -`-harness-learn` worktree. It runs post-merge memory updates without ever -blocking (or being blocked by) the build loop; the two coordinate only through git -(the `refs/harness/last-learned` watermark ref). Same three-layer discipline, its own -`/loop` session. - -## Three checkouts (the worktree topology) - -``` -/ the human's checkout. On `main`. Never touched by the harness. (Inv 6) --harness/ the harness HOST worktree. Detached at origin/main; runs BOTH loops' - outer sessions. harness-tick.sh re-syncs it to main every tick. Does - NOT move between feature branches. --harness-/ EPHEMERAL per-feature worktree. One per in-flight feature; the - dispatcher creates it (off feature/) and tears it down on - merge/close. (Inv 3: worktree ↔ branch 1:1.) --harness-learn/ the memory loop's dedicated worktree. Persistent + reused; learn-tick.sh - resets it to a clean learn/ off main each run. Where /learn runs. -``` - -Two reasons the host is **detached**, not on a `main` branch: git refuses to check -out `main` in two worktrees at once (the human's checkout holds it), and the host -never needs a writable branch of its own — it only reads loop infra and spawns -per-feature worktrees. `WORKTREE_BASE` derives `` from the **main worktree** -(not `$PWD`), so per-feature paths are always `-harness-` no matter -which worktree the dispatcher runs from. - -## Why the split matters for setup - -- **The outer loop must never do real work.** `/loop 5m /poll-and-dispatch` - re-runs in the *same* session every tick; if it did work there, context would - bloat and rot by tick 10. The shim skill does one thing: call the script. All - real work happens in `claude -p` subprocesses with fresh context. -- **The dispatcher is deterministic.** No model in the decision path. This is - what makes crash recovery free and behavior predictable from disk state. - -## The state machine in one table - -| Branch state | Means | Next action the dispatcher takes | -|------------------------|--------------------|-----------------------------------------| -| `prd//` | waiting in queue | atomic-rename to `feature/` (claim) | -| `feature/` no specs | claimed, unplanned | `/spec-planning` | -| `.planning-done` | planned | `/spec-validate` | -| `.validated` | validated | `/implement-mainspec` until runner == 0 | -| runner exits 0 | implemented | open PR against `main` | -| PR has findings | in review | `/address-feedback` (bounded) | -| PR merged | done | cleanup worktree (the memory loop runs `/learn` separately) | - -"Done" is one thing only: `./prds//run-prd-test.sh` exits 0. The harness -contracts on that exit code and nothing else. - -## The artifacts ARE the state - -There is no database, no in-memory queue, no "what step are we on" file. A -sentinel file existing IS that phase being done. The branch namespace IS the -work registry. Counters live in `.harness/`. Everything the dispatcher needs is -re-derivable from `git` + the filesystem on every tick. That is the whole -recovery story: `kill -9` mid-step leaves nothing the next tick can't sort out. - -## Where the human steers - -Exactly two points: -1. **Confirming a PRD** (via `/intent`, in their own checkout). -2. **Merging a PR** (the feature PR, and later the `/learn` memory PR). - -Everything between is the harness. The loop never merges — that is the steering -input the system is built around. - -## What harness-init is actually standing up - -Both outer loops (two `/loop` sessions — build + memory), the dispatcher and -`learn-tick.sh` scripts plus their shared `harness-lib.sh`, the config, the -agent contract (`AGENTS.md`), and the provisioning that makes per-feature -worktrees runnable. The inner skills (`/intent`, `/spec-planning`, etc.) are -installed from the catalog; harness-init wires them, it does not author them. diff --git a/skills/harness/harness-init/references/worktree-bootstrap.md b/skills/harness/harness-init/references/worktree-bootstrap.md deleted file mode 100644 index bb80de1..0000000 --- a/skills/harness/harness-init/references/worktree-bootstrap.md +++ /dev/null @@ -1,95 +0,0 @@ -# Worktree bootstrap — making a fresh worktree runnable - -`scripts/bootstrap-worktree.sh` provisions a newly created git worktree so the -project can actually run inside it. This is Software 3.0: the script is -generated by reading the project (see project-discovery.md), explained to the -user, and confirmed before it's written. - -## Why it exists - -`git worktree add` gives you a checkout of tracked files only. Everything in -`.gitignore` — `node_modules`, `target`, `.venv`, `.env`, generated code, build -output — does NOT come along. So a fresh worktree is like a new developer's -laptop on day one: the code is there, but it won't run until someone installs -deps, drops in secrets, and runs codegen. - -The dispatcher creates a worktree per feature. Without bootstrap, slice signals -and `run-prd-test.sh` fail for reasons that have nothing to do with the feature -(missing deps, missing `.env`). Bootstrap closes that gap. - -## Two callers - -1. **harness-init**, once, against the host worktree — also serves as the - script's own validation (if the host worktree runs after bootstrap, the - script works). -2. **the dispatcher**, after every `git worktree add` (the hook documented in - dispatcher-explained.md). - -So the script must be **idempotent** and **non-interactive** — it runs -unattended inside the loop. - -## Contract - -``` -scripts/bootstrap-worktree.sh -``` - -- Takes the target worktree path as its one argument. -- Determines the **source checkout** (the human's primary checkout, where the - real gitignored files live) via `git -C rev-parse --git-common-dir` - → its parent is the main worktree. Use that as the copy source. -- Exits 0 on success, non-zero with a clear message on failure. -- Re-running on an already-provisioned worktree is a cheap no-op (skip installs - if the lockfile is unchanged, skip copying a file that already exists and - matches, etc.). - -## What it typically does, in order - -1. **Copy gitignored runtime files** from the source checkout: `.env`, - `.env.local`, local credentials, certs, local config — whatever - `.env.example` and `.gitignore` reveal the project needs. Copy only files - that exist in the source; never fail because an optional one is absent. -2. **Install dependencies** using the project's package manager and lockfile - (`npm ci`, `pnpm i --frozen-lockfile`, `uv sync`, `cargo fetch`, - `go mod download`, `bundle install`, ...). -3. **Run codegen** if the project needs it before it runs (`prisma generate`, - protobuf/GraphQL codegen, `sqlc generate`, migrations against a local/test - DB, ...). -4. **Any project-specific "make it runnable" step** the README/CI revealed. - -## The secret-copying caution — flag this loudly - -Step 1 copies REAL secrets (`.env` with live keys, credential files) from the -human's checkout into the sibling worktree. This is the one place the harness -touches sensitive files. When you present this step: - -- Say explicitly what files will be copied and from where. -- Confirm the destination is a `*-harness*` worktree on the same machine, owned - by the same user — secrets don't leave the box. -- Copy direction is **always** source-checkout → worktree. Never the reverse. - Never delete from the source. (Invariant 6.) -- If the project has no gitignored secrets (e.g. all config via real env vars or - a secrets manager), skip step 1 entirely and say so. -- Get explicit consent before writing a script that copies secrets. - -## Things to get right - -- **Idempotency.** It runs on every `git worktree add`. Guard expensive steps - (`[[ -d node_modules ]] && lockfile unchanged → skip install`). -- **Non-interactive.** No prompts; it runs in the loop. Use `--frozen`/`ci` - install flavors that don't prompt. -- **Port awareness.** If codegen or a setup step starts a server, it can collide - with the human's dev server. Prefer steps that don't bind ports; if - unavoidable, read the port from env (note this in the script's comments). -- **Fail loudly, not silently.** A worktree that's missing deps should make - bootstrap exit non-zero with a clear message, not limp along — otherwise the - failure surfaces later as a confusing PRD-runner failure. -- **Comment the script.** The human owns it. Every step gets a one-line comment - saying what it provisions and why, so they can tweak it. - -## If discovery comes up empty - -If you cannot determine how the project installs/runs (no manifest, sparse -README, no CI), do not guess. Ask the user directly: "How do you set up this -project on a fresh machine? What do you install, and what secret/config files -do you copy in?" Their answer becomes the script. diff --git a/skills/harness/harness-init/scripts/preflight.sh b/skills/harness/harness-init/scripts/preflight.sh deleted file mode 100755 index 2a918a8..0000000 --- a/skills/harness/harness-init/scripts/preflight.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env bash -# preflight.sh — deterministic environment + inventory report for /harness-init. -# Prints a checklist; does NOT gate. The skill reads this and decides what to do. -# Run from the consumer project's root (the human's checkout). - -ok() { printf ' [ok] %s\n' "$1"; } -warn() { printf ' [warn] %s\n' "$1"; } -miss() { printf ' [MISS] %s\n' "$1"; } -have() { command -v "$1" >/dev/null 2>&1; } - -echo "=== Environment ===" -if git rev-parse --git-dir >/dev/null 2>&1; then - ok "git repository" - branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "?") - [[ "$branch" == "main" || "$branch" == "master" ]] && ok "on $branch" || warn "on '$branch' (expected main)" - git diff --quiet && git diff --cached --quiet 2>/dev/null && ok "working tree clean" || warn "working tree has uncommitted changes" - git remote get-url origin >/dev/null 2>&1 && ok "origin remote: $(git remote get-url origin 2>/dev/null)" || warn "no 'origin' remote (needed for branch-as-queue)" - echo " git email: $(git config user.email 2>/dev/null || echo '(unset!)')" - echo " derived slug: $(git config user.email 2>/dev/null | cut -d@ -f1)" -else - miss "not a git repository — run 'git init' and add an origin remote first" -fi -have git && ok "git CLI" || miss "git CLI" -have gh && { gh auth status >/dev/null 2>&1 && ok "gh CLI (authenticated)" || warn "gh CLI present but not authenticated (run: gh auth login)"; } || miss "gh CLI (needed for PR ops)" -have claude && ok "claude CLI" || warn "claude CLI not on PATH (the dispatcher shells out to 'claude -p')" - -echo -echo "=== Toolchain signals (for AGENTS.md / local-checks / bootstrap) ===" -declare -A M=( - [package.json]="Node" [pnpm-lock.yaml]="pnpm" [yarn.lock]="yarn" [bun.lockb]="bun" - [pyproject.toml]="Python" [requirements.txt]="pip" [uv.lock]="uv" [Pipfile]="pipenv" - [Cargo.toml]="Rust" [go.mod]="Go" [Gemfile]="Ruby" [pom.xml]="Maven" - [build.gradle]="Gradle" [composer.json]="PHP" [mix.exs]="Elixir" -) -found=0 -for f in "${!M[@]}"; do [[ -e "$f" ]] && { ok "${M[$f]} ($f)"; found=1; }; done -(( found )) || warn "no dependency manifest found at root — discovery will rely on README/CI or asking" -for f in .env.example .env.sample .env.template; do [[ -e "$f" ]] && warn "secrets template: $f (bootstrap will need to copy the real file)"; done -[[ -e Makefile || -e Justfile || -e Taskfile.yml ]] && ok "task runner present (read it for canonical commands)" -[[ -d .github/workflows ]] && ok ".github/workflows present (read CI for setup+test recipe)" -[[ -e prisma/schema.prisma ]] && warn "prisma — bootstrap likely needs 'prisma generate'" -ls ./*.proto >/dev/null 2>&1 && warn "protobuf — bootstrap likely needs a codegen step" - -echo -echo "=== Inner skills (chain the dispatcher calls) ===" -SK=.claude/skills -for s in intent spec-planning spec-validate implement-mainspec fix-local-checks address-feedback learn expert; do - if find "$SK" -type f -path "*/$s/SKILL.md" 2>/dev/null | grep -q . ; then ok "/$s" - elif find "$SK" -type d -name "$s" 2>/dev/null | grep -q . ; then warn "/$s (dir present but no SKILL.md — stub?)" - else miss "/$s (not installed)"; fi -done - -echo -echo "=== Harness artifacts (re-run / already-present check) ===" -[[ -f scripts/poll-and-dispatch.sh ]] && warn "scripts/poll-and-dispatch.sh exists (re-run?)" || ok "scripts/poll-and-dispatch.sh absent (fresh)" -[[ -f scripts/harness-tick.sh ]] && warn "scripts/harness-tick.sh exists (re-run?)" || ok "scripts/harness-tick.sh absent (fresh)" -[[ -f scripts/harness-lib.sh ]] && warn "scripts/harness-lib.sh exists (re-run?)" || ok "scripts/harness-lib.sh absent (fresh)" -[[ -f scripts/learn-tick.sh ]] && warn "scripts/learn-tick.sh exists (re-run?)" || ok "scripts/learn-tick.sh absent (fresh)" -[[ -f .harness/env ]] && warn ".harness/env exists (re-run?)" || ok ".harness/env absent (fresh)" -[[ -s AGENTS.md ]] && warn "AGENTS.md is non-empty (re-run? will diff)" || ok "AGENTS.md absent/empty (fresh)" -[[ -f scripts/bootstrap-worktree.sh ]] && warn "scripts/bootstrap-worktree.sh exists (re-run?)" || ok "scripts/bootstrap-worktree.sh absent (fresh)" -[[ -f REVIEW.md ]] && warn "REVIEW.md exists" || ok "REVIEW.md absent" -# Preflight runs from the HUMAN's checkout (bare repo name), so basename "$PWD" is -# the right base for the expected host-worktree path here. (The dispatcher, which -# runs from the host worktree, instead derives this from the main worktree.) -base="../$(basename "$PWD")-harness" -[[ -d "$base" ]] && warn "host worktree $base already exists" || ok "host worktree $base absent (fresh)" - -echo -echo "Preflight complete. [MISS] items block; [warn] items need a decision." diff --git a/skills/harness/learn/SKILL.md b/skills/harness/learn/SKILL.md index 18fc6cf..e1336c5 100644 --- a/skills/harness/learn/SKILL.md +++ b/skills/harness/learn/SKILL.md @@ -12,10 +12,10 @@ updates the **Expert** (procedural + semantic memory, pulled on demand) and the project invariants, and drafts candidate **lints** (the highest-value memory, because a lint is a rule the agent cannot ship past). -You run **headless**, invoked by the **memory loop** (`scripts/learn-tick.sh`, driven -by its own `/loop … /learn-loop`) as the post-merge step — in a dedicated +You run **headless**, invoked by the **memory loop** (`scripts/learn-dispatch.sh` in the harness repo, driven +by the `context-specs` supervisor on its own interval) as the post-merge step — in a dedicated `../-harness-learn` worktree on a `learn/` branch off `origin/main`, never -in the build loop's host worktree. The memory loop runs independently of the +in the developer's clone. The memory loop runs independently of the feature/build loop, so a from-scratch Expert bootstrap blocks neither. Your output is a single reviewable PR — never an auto-merge. Humans steer at merge. diff --git a/skills/human-loop/evaluate-sessions/SKILL.md b/skills/human-loop/evaluate-sessions/SKILL.md index 84fae49..35db078 100644 --- a/skills/human-loop/evaluate-sessions/SKILL.md +++ b/skills/human-loop/evaluate-sessions/SKILL.md @@ -128,7 +128,7 @@ Pick the lens — it only changes emphasis, not mechanics: Run `scripts/resolve-sessions.sh `. It parses the **PR comment** (the durable, dispatcher-posted artifact) for session IDs and globs `~/.claude/projects/*/.jsonl` for each trace, flagging any whose file is missing (a remote/CI run — see the degradation note in -`references/trace-reading.md`). Do **not** depend on `.harness/sessions-.tsv`; it's +`references/trace-reading.md`). Do **not** depend on the harness repo’s `state//sessions-.tsv`; it’s ephemeral and deleted on PR cleanup. ### Step 2 — Triage from the table (S7) @@ -189,7 +189,7 @@ re-examines the current state. ## Hard nevers - **Never write `main` or memory autonomously.** Changes land on a branch; `/learn` writes memory post-merge from the merged diff (S5). -- **Never depend on `.harness/sessions-.tsv`.** It's ephemeral and gone post-merge; the PR +- **Never depend on the harness repo’s `state//sessions-.tsv`.** It's ephemeral and gone post-merge; the PR comment is the contract (S8 / `trace-reading.md`). - **Never fabricate an eval that passes trivially.** An eval that doesn't fail against the context that misled the agent proves nothing (`references/evals.md`, right-reason check). diff --git a/skills/human-loop/evaluate-sessions/references/trace-reading.md b/skills/human-loop/evaluate-sessions/references/trace-reading.md index 27def1a..978c540 100644 --- a/skills/human-loop/evaluate-sessions/references/trace-reading.md +++ b/skills/human-loop/evaluate-sessions/references/trace-reading.md @@ -23,7 +23,7 @@ The table is `| Time | Step | Attempt | Session ID | Exit |`, with the step and backtick-wrapped. `scripts/resolve-sessions.sh ` parses exactly this and emits `\t` per row. -**Do not read `.harness/sessions-.tsv`.** It carries an extra `duration_s` column and +**Do not read the harness repo’s `state//sessions-.tsv`.** It carries an extra `duration_s` column and untruncated rows, but the cleanup pass `rm -f`s it on every merged/closed PR — so for a merged PR (the `/learn`-audit case) it's already gone. The PR comment is the contract; the TSV is ephemeral working state. (One consequence: `render_sessions_table` does `tail -n 20` diff --git a/skills/human-loop/evaluate-sessions/scripts/resolve-sessions.sh b/skills/human-loop/evaluate-sessions/scripts/resolve-sessions.sh index fee524f..9ebb5af 100755 --- a/skills/human-loop/evaluate-sessions/scripts/resolve-sessions.sh +++ b/skills/human-loop/evaluate-sessions/scripts/resolve-sessions.sh @@ -4,7 +4,7 @@ # The session table is posted on the PR DETERMINISTICALLY BY THE DISPATCHER # (render_sessions_table -> signal_human_review / signal_stuck / signal_learn_review, # each ending in `gh pr comment`). That comment is the durable artifact — the local -# .harness/sessions-.tsv is ephemeral and `rm -f`'d on PR cleanup, so we never read it. +# The harness repo's state//sessions-.tsv is ephemeral and rm -f'd on PR cleanup, so we never read it. # # Output (one line per session, tab-separated): # \t diff --git a/skills/human-loop/wiki-init/SKILL.md b/skills/human-loop/wiki-init/SKILL.md index 0074d36..c70ee82 100644 --- a/skills/human-loop/wiki-init/SKILL.md +++ b/skills/human-loop/wiki-init/SKILL.md @@ -181,7 +181,7 @@ path to point it at; otherwise this wiki is theirs to read and query directly. ## Invocation & output contract - **Invoked by:** a human (`/wiki-init`, optionally `--yolo`). Not the dispatcher — this - is a human-attentive setup skill, like `/intent` and `/harness-init`. + is a human-attentive setup skill, like `/intent` and `/env-init`. - **Outputs:** a standalone wiki vault at the chosen external path — `raw/`, `wiki/`, `_meta/`, the tailored conventions doc (`CLAUDE.md`), the three commands under `.claude/commands/`, a seeded `MOC.md`, a `README.md`, and an initialized git repo. From e82ec6b4cf70433e8c89595989af60c98785d39e Mon Sep 17 00:00:00 2001 From: Rico Date: Sun, 5 Jul 2026 13:22:59 -0500 Subject: [PATCH 11/14] Reframe docs around harness engineering and the two-tier architecture - README leads with the harness-engineering definition (deterministic code driving probabilistic code to a guaranteed output: PR ready-to-merge or STUCK-with-diagnosis, never 'maybe') and the CLI quickstart; the layer-1/2/3 ladder becomes the harness-engineering arc with SDD reframed as the system's short-term memory and LTM-informs-STM as the organizing metaphor (Reflection in the hot path, /learn as post-merge 'dreaming'); light environment/goal vocabulary throughout. - docs/3 rewritten for the two tiers, ref-only-ops trust story, exit-code drain protocol, and the CLI replacing the /loop startup. - docs/invariants.md: Inv 1/5/6 reworded (state in state//, per-env lock + exit protocol, developer-clone sandbox via ref ops + sibling worktrees); tables and failure walkthroughs updated to the supervisor world. - docs/2 Expert section no longer links the deleted expert-sdd-creator. Co-Authored-By: Claude Fable 5 --- README.md | 365 +++++++++++++----------------- docs/2-spec-driven-development.md | 26 +-- docs/3-the-agent-harness.md | 145 ++++++++---- docs/4-continuous-improvement.md | 4 +- docs/5-the-human-loop.md | 2 +- docs/README.md | 81 ++++--- docs/invariants.md | 68 +++--- 7 files changed, 360 insertions(+), 331 deletions(-) diff --git a/README.md b/README.md index 73e4806..8345352 100644 --- a/README.md +++ b/README.md @@ -1,90 +1,101 @@ # Context Specs -**Context engineering for agent-first development.** - -The biggest lever you have when building with a coding agent is what goes into -its context window — and what stays out. Context Specs is that lever, pulled at -three layers that build on each other. Pull all three and the work inverts: you -describe a feature and pin down what "done" means, then the project plans it, -implements it, verifies it, and hands you a finished pull request. What's left -for you is the judgment a model can't supply — understanding the problem, -deciding what's worth building, and telling whether what came back is right. - -It ships as composable [Agent Skills](#installation). Install once, invoke via -slash commands, extend with your organization's own expertise. - -> **New here? Read [the full story](./docs/README.md)** — six short chapters that -> take you from the idea to the mindset shift, in order. +**Harness engineering in practice.** + +Harness engineering is building a system — defined inputs, defined outputs — +out of deterministic code and probabilistic code, where the deterministic code +invokes the probabilistic code and controls the flow all the way to a +guaranteed, well-defined output. +*([What is Harness Engineering?](https://www.linkedin.com/pulse/what-harness-engineering-rico-romero-vb7fc/))* + +Context Specs is that system for building software. The **input** is a PRD with +a runnable definition of done. The **output** is a pull request that is either +**ready to merge** or **STUCK with a diagnosis** — never "maybe." In between: a +deterministic dispatcher that plans, validates, implements, verifies, and +answers the reviewer by driving fresh coding-agent processes, one bounded step +at a time. What's left for you is the judgment a model can't supply — +understanding the problem, deciding what's worth building, and telling whether +what came back is right. + +The output is also your feedback signal. Every STUCK and every review finding +points at a piece of *context* to improve — the project's long-term memory, its +contract, its lints. Improve those and the ready-to-merge ratio climbs: the +system gets better at building your project every time it builds. + +> **New here? Read [the full story](./docs/README.md)** — six short chapters +> that take you from the idea to the mindset shift, in order. --- -## The idea: the right context at the right time - -A coding agent is only ever as good as the context it's reasoning over — the -actual tokens in its window at the moment it decides. That window is finite, and -it degrades: older instructions lose influence, autonomously-retrieved files -crowd out relevant ones, and compaction silently drops things when it fills. +## Quickstart -Context engineering is the discipline of getting the right context into that -window at the right time, and keeping everything else out — the agent reading -what it needs, when it needs it, from files it can navigate on its own. The three -layers below are that same idea at a widening scope: first one feature, then a -whole project that builds itself, then the way you work day to day. - -→ [Chapter 1 — Context engineering](./docs/1-context-engineering.md) +```bash +# 1 · Create your harness (one repo that drives all your projects) +npx context-specs init my-harness +cd my-harness ---- +# 2 · Register a project as an environment +context-specs add ~/code/myapp -## Layer 1 — Spec-Driven Development +# 3 · The Software 3.0 half: generate the project-specific pieces +cd ~/code/myapp && claude +> /env-init # AGENTS.md, /intent, the Expert, checks, bootstrap — one PR -*Context engineering, applied to building one feature. Usable on its own.* +# 4 · After that PR merges: walk away +context-specs start +``` -![Experts](./experts.png) +From then on you live in a three-beat cycle — **express intent, the harness +builds, you evaluate**: -You create **domain experts** from your own documentation with -[`/expert-sdd-creator`](./skills/sdd/expert-sdd-creator/SKILL.md) — -define the knowledge once, and it flows automatically through every phase: +```mermaid +flowchart LR + Intent["/intent\nyou express intent"] --> Build["build loop\nplans → builds the PR"] + Build --> Eval["/evaluate-pr · /evaluate-sessions\nyou understand it"] + Eval --> Merge["merge"] + Merge --> Learn["learn loop\nupdates memory → PR"] + Learn --> Intent +``` -1. **Spec Planning** ([`/spec-planning`](./skills/sdd/spec-planning/SKILL.md)) — - research the codebase, pull in matching experts, and write the plan to disk as - a **mainspec** plus temporally-ordered **slices**. Planning lives *outside* the - context window, so it can't decay or compact away; slicing feeds the - implementer only the piece it's working on. -2. **Spec Validation** ([`/spec-validate`](./skills/sdd/spec-validate/SKILL.md)) — - 3+ independent Opus reviewers plus expert review, with consensus scoring - (3/3 = very high, 2/3 = high) turning agreement into a confidence signal. - Impactful findings are applied in place. -3. **Implementation** ([`/implement-mainspec`](./skills/sdd/implement-mainspec/SKILL.md)) — - slices implemented in dependency order, one at a time on the feature branch. - Each slice is verified by its unit tests, then a **Reflect** step (below) feeds - what the implementer learned back into the expert. +`context-specs status` shows every environment's features and phases; +`run ` does one foreground pass; `logs -f` follows the loop; +`doctor` checks the wiring. -**Composable, not hardcoded.** Multiple experts activate for one feature — a -React expert and a DynamoDB expert both contribute on a full-stack change. Add or -remove experts without touching any existing skill; organizations layer in -private experts for internal libraries the same way. +--- -**Reflection is the other half of what an expert is.** Where the expert curates -context *before* implementation, Reflection updates it *after*: once a slice's code -and unit tests are green, the implementer judges whether what it learned — a new -pattern, or a spec that contradicted the codebase — should change the project's -long-term memory, and writes it back to the expert. The bar is high; most slices -change nothing. +## The architecture: one harness, N environments -→ [Chapter 2 — Spec-Driven Development](./docs/2-spec-driven-development.md) +``` +HARNESS REPO (tier 1 — yours, one) ENVIRONMENT REPOS (tier 2 — your projects) + bin/context-specs the CLI AGENTS.md the eager contract + scripts/ the dispatchers .claude/skills/intent/ project-owned /intent + skills/ canonical skills .claude/skills/expert/ long-term memory + state// runtime state scripts/ bootstrap + local checks + .harness/env this env's dials +``` ---- +The dividing line is one test: **could you write it without reading the +project's code?** Yes → harness repo; improve it once and every environment +benefits. No → it's *Software 3.0* — generated by an agent reading that +project, committed to that project, evolving with it. `context-specs add` +connects the tiers by symlinking the canonical skills into each environment +(gitignored); `/env-init` generates the project-owned half. -## Layer 2 — The agent harness +Two artifacts are deliberately project-owned rather than shared, because they +are the two **developer-owned levers**: -*Your project runs the Layer 1 loop for you — and gets better every merge.* +- **`/intent`** — the input side. How well a project turns an idea into a PRD + + runnable definition of done is one of the biggest levers it has; tune the + skill to your project. +- **The Expert** — the memory side. The project's long-term memory, which + informs every future plan. The loops file things into it; you shape it. -The whole promise, in one sequence: +## The system, end to end -> Describe a feature to [`/intent`](./skills/human-loop/intent/SKILL.md) and confirm -> it. Walk away. The project plans the feature, validates the plan, implements -> it, runs its checks, opens a pull request, answers the reviewer — and hands you -> back a PR that's ready to merge. +> Describe a feature to `/intent` and confirm it. Walk away. The project plans +> the feature, validates the plan, implements it, runs its checks, opens a pull +> request, answers the reviewer — and hands you back a PR that's ready to merge, +> or an honest STUCK with the diagnosis started. ```mermaid flowchart LR @@ -99,39 +110,61 @@ flowchart LR ``` You can trust a machine to run this unattended because it keeps **no hidden -state**. The complete state of every feature is observable from the files on disk -and the branches in git. A small, deterministic dispatcher — **no LLM in the loop** -— reads that state each tick and shells out to a fresh `claude -p` process per -step, so no step inherits another's polluted window and crash recovery is free. -Four layers of verification (pre-commit, slice unit tests, `local-checks`, and a -runnable `run-prd-test.sh` definition of done) can't be talked past — and when a -step genuinely can't make progress, the harness stops and hands you a -**diagnosis-first** report rather than faking success. - -**It also remembers.** When code lands on `main`, the harness updates its own -long-term memory: [`/learn`](./skills/harness/learn/SKILL.md) reads the -merged diff and routes what's worth keeping into the Expert, the `AGENTS.md` map, -or a custom lint the agent can't ship past — so the next feature starts knowing -what the last one taught. One write path, ground truth only, behind a human -merge. - -Setting all this up is itself a guided skill: -[`/harness-init`](./skills/harness/harness-init/SKILL.md). - -→ [Chapter 3 — The agent harness](./docs/3-the-agent-harness.md) · +state**: every feature's state is observable from files on disk and branches in +git. A small deterministic dispatcher — **no LLM in the decision path** — reads +that state each tick and shells out to a fresh `claude -p` process per step, so +no step inherits another's polluted window and crash recovery is free. It never +touches your checkout: it works your repo's *refs* and its own sibling +worktrees. Four layers of verification (pre-commit, slice tests, +`local-checks`, and a runnable `run-prd-test.sh` definition of done) can't be +talked past — and the loop is **goal-based**: the runner *is* the goal, and the +dispatcher keeps invoking the agent until it exits 0 or a bounded retry cap +turns honest failure into STUCK. + +The scheduling is one exit code: a tick that advanced work re-fires +immediately (work drains at machine speed), an idle tick naps the interval, a +stuck feature never hot-loops. That's the whole deterministic half — +[read the invariants](./docs/invariants.md) for the proof it's safe to leave +running. + +→ [Chapter 3 — The agent harness](./docs/3-the-agent-harness.md) + +## Memory: long-term informs short-term + +**SDD is the harness's short-term memory.** `/spec-planning` writes the plan for +one feature — a mainspec plus temporally-ordered slices — to disk, *outside* the +context window, so it can't decay or compact away; the implementer is fed one +slice at a time, the right context at the right time, no human routing needed. + +**The Expert is the long-term memory** — and short-term memory is written *from* +it: every plan is informed by what the project already knows. Improve one shard +of long-term memory and every future feature plans better. It's written back on +two rhythms: + +- **Reflection** — in the hot path. After each slice goes green, the implementer + judges whether what it learned should change the project's memory. High bar; + most slices change nothing. +- **`/learn`** — off the hot path. After each merge, the memory loop reads the + merged diff and routes what's worth keeping into the Expert, `AGENTS.md`, or a + custom lint the agent can't ship past — then raises its own `learn/` PR. + The project consolidating what it learned while nothing is running — the way + agentic systems "dream." + +One write path per rhythm, ground truth only, always behind a human merge — and +the third write path is **you**. The Expert is developer-owned; the loops are +helpers. + +→ [Chapter 2 — Spec-Driven Development](./docs/2-spec-driven-development.md) · [Chapter 4 — Continuous improvement](./docs/4-continuous-improvement.md) ---- - -## Layer 3 — The human loop +## The human loop *Once the machine does the typing, what's left is the part only you can do.* -The governing line is Karpathy's: *you can outsource your thinking, but you can't -outsource your understanding.* The harness took the verifiable work — syntax, API -recall, mechanics. The human loop is you, working the unverifiable: whether this -is the right thing to build, whether the abstraction is sound, whether it feels -right. +The governing line is Karpathy's: *you can outsource your thinking, but you +can't outsource your understanding.* The harness took the verifiable work. The +human loop is you, working the unverifiable: whether this is the right thing to +build, whether the abstraction is sound, whether it feels right. ``` Understanding ──▶ Intent ──▶ [ the harness builds ] ──▶ Evaluate @@ -139,17 +172,14 @@ Understanding ──▶ Intent ──▶ [ the harness builds ] ──▶ Evalua /evaluate-sessions ``` -- **Understanding** ([`/wiki-init`](./skills/human-loop/wiki-init/SKILL.md)) — - a Karpathy "LLM Wiki" that builds *your* model of the problem space, so you - arrive at Intent with sharper questions. -- **Intent** ([`/intent`](./skills/human-loop/intent/SKILL.md)) — turn that - understanding into a PRD plus a runnable definition of done. -- **Evaluate** ([`/evaluate-pr`](./skills/human-loop/evaluate-pr/SKILL.md) + - [`/evaluate-sessions`](./skills/human-loop/evaluate-sessions/SKILL.md)) — - walk the change to build real understanding, *and* read the build trail to find - where the project's context served the agents or failed them. The flywheel: - *observe a trace → capture it as an eval → fix the context → it persists as a - regression test.* +- **Understanding** (`/wiki-init`) — a Karpathy "LLM Wiki" that builds *your* + model of the problem space, so you arrive at Intent with sharper questions. +- **Intent** (`/intent`) — turn that understanding into a PRD plus a runnable + definition of done: the system's input, and its goal. +- **Evaluate** (`/evaluate-pr` + `/evaluate-sessions`) — walk the change to + build real understanding, *and* read the build trail to find where the + project's context served the agents or failed them. The flywheel: *observe a + trace → capture it as an eval → fix the context → it persists.* Your loop's output is the harness's input; the harness's output is your loop's input. When you evaluate, you don't just approve work — you improve the thing @@ -157,127 +187,46 @@ that produced it. → [Chapter 5 — The human loop](./docs/5-the-human-loop.md) ---- - ## The shift -Put the three layers together and your project stops being a codebase you type -into and becomes a **harness you tune**. The code is an output of the system; your +Put it together and your project stops being a codebase you type into and +becomes a **harness you tune**. The code is an output of the system; your attention moves from syntax to context. Three things stay yours: deep understanding of the problem space, theorizing and expressing intent, and evaluating outcomes to improve the context so every future feature benefits. A codebase you type into is a constant cost. A harness you tune is an -appreciating asset — each feature leaves it a little more capable of building the -next one. +appreciating asset — each feature leaves it a little more capable of building +the next one. → [Chapter 6 — The mindset shift](./docs/6-the-mindset-shift.md) --- -## Getting started - -**Set it up once.** [Install the skills](#installation), then run -[`/harness-init`](./skills/harness/harness-init/SKILL.md) — a guided setup that -builds your project's custom harness and provisions its worktrees. It runs as -**two independent loops, each in its own long-lived session.** Start them: - -```bash -# session 1 — the build loop (features) -/loop 5m /poll-and-dispatch - -# session 2 — the memory loop (/learn), in a SEPARATE session -/loop 10m /learn-loop -``` - -*(Optionally run [`/wiki-init`](./skills/human-loop/wiki-init/SKILL.md) first to -build your own understanding of the problem space before you write intent.)* - -With both loops running, you live in a three-beat cycle: you express intent, the -harness builds, and you evaluate what comes back. +## The pieces -```mermaid -flowchart LR - Intent["/intent\nyou express intent"] --> Build["build loop\nplans → builds the PR"] - Build --> Eval["/evaluate-pr · /evaluate-sessions\nyou understand it"] - Eval --> Merge["merge"] - Merge --> Learn["learn loop\nupdates memory → PR"] - Learn --> Intent -``` - -**1 · You express intent (human loop, before).** `/intent` a feature — a PRD plus -a runnable definition of done. That PRD is the harness's input. - -**2 · The harness builds (two loops).** -- **The build loop** (`/loop 5m /poll-and-dispatch`) picks up your intent and runs - the SDD chain — plan, validate, implement, verify — all the way to an open PR. -- **The memory loop** (`/loop 10m /learn-loop`) watches `main`. Every merge is a - chance to add memory, or remove a memory a change has made stale. It raises a - *separate* PR for those memory updates, so long-term learning never blocks the - build loop. The two coordinate only through git. - -**3 · You evaluate (human loop, after).** -- **`/evaluate-pr`** — the goal here is *understanding* the change, not reaching a - verdict. Approving, requesting changes, or closing are byproducts of that - understanding; the understanding itself is what lets you write sharper intent - next time. -- **`/evaluate-sessions`** — for when the outcome was off, whether the harness got - **STUCK** or the PR was wrong on review. This is usually a context issue: with - the right context, the agent could have done the task. Evaluate-sessions reads every session - that led to the PR — intent, spec-planning, spec-validate, implementation — to - locate the **context gap**. Fixing the context matters more than fixing - the code: the code fix repairs this one feature, while the context fix keeps the same mistake out of every future feature. - -Your intent is the harness's input; the harness's PR is your evaluation's input; evaluating -improves the context that feeds the next round. That's the cycle you live in. - -*(Only want the spec workflow? Layer 1 stands on its own — drive `/spec-planning` -→ `/spec-validate` → `/implement-mainspec` by hand, no harness needed.)* - ---- - -## Installation - -Context Specs has two kinds of installable content — **skills** and -**subagents** — each with its own step. - -### Skills - -```bash -npx skills add https://github.com/capitalone/context-specs -``` - -Installs all skills into your project's `.claude/skills/` directory. - -### Subagents - -```bash -curl -fsSL https://raw.githubusercontent.com/capitalone/context-specs/main/install-agents.sh | bash -``` - -Run from your target project directory. Copies agent definitions (e.g. -`slice-implementer.md`) into `.claude/agents/`. Safe to re-run. - ---- - -## The skills - -| Layer | Skill | Does | +| Where | Piece | Does | |---|---|---| -| **1 · SDD** | `/expert-sdd-creator` | Create a domain expert from your docs | -| | `/spec-planning` | Idea → mainspec + temporal slices | -| | `/spec-validate` | Multi-agent consensus + expert review | -| | `/implement-slice`, `/implement-mainspec` | Implement slices sequentially with unit tests + Reflect | -| **2 · Harness** | `/harness-init` | Guided setup of the local harness | +| **CLI** | `init` / `add` / `link` | Create the harness repo; register environments; symlink skills | +| | `start` / `stop` / `run` | Supervise the loops (drain-on-advance) / one foreground pass | +| | `status` / `logs` / `doctor` | Observe every environment; check the wiring | +| **Dispatchers** | `scripts/poll-and-dispatch.sh` | The build loop: PRD → PR, one deterministic step per tick | +| | `scripts/learn-dispatch.sh` | The memory loop: merged diff → `learn/` PR | +| **SDD skills** | `/spec-planning` | PRD → mainspec + temporal slices (short-term memory) | +| | `/spec-validate` | Multi-agent consensus review of the plan | +| | `/implement-mainspec`, `/implement-slice` | Implement slices in order, unit tests + Reflect | +| **Harness skills** | `/env-init` | Guided setup of a project as an environment | | | `/fix-local-checks` | Honest fixes for a failing pre-PR gate | | | `/address-feedback` | Triage and answer reviewer findings | | | `/learn` | Post-merge long-term memory update | -| **3 · Human loop** | `/wiki-init` | Stand up a Karpathy LLM-wiki (Understanding) | -| | `/intent` | Idea → PRD + runnable definition of done | +| **Human loop** | `/wiki-init` | Stand up a Karpathy LLM-wiki (Understanding) | +| | `/intent` | Idea → PRD + runnable definition of done (project-owned) | | | `/evaluate-pr` | Evaluate the change; build understanding | | | `/evaluate-sessions` | Evaluate the build trail; capture evals | ---- +*(Only want the spec workflow? It stands alone — symlink or copy the SDD skills +and drive `/spec-planning` → `/spec-validate` → `/implement-mainspec` by hand. +No harness needed.)* ## Documentation @@ -285,8 +234,6 @@ Run from your target project directory. Copies agent definitions (e.g. - **[Design invariants](./docs/invariants.md)** — the properties that make the harness safe to leave running. ---- - ## License Apache 2.0 diff --git a/docs/2-spec-driven-development.md b/docs/2-spec-driven-development.md index b0ce60c..46c685c 100644 --- a/docs/2-spec-driven-development.md +++ b/docs/2-spec-driven-development.md @@ -1,6 +1,6 @@ # Chapter 2 — Spec-Driven Development -*Layer 1 — context engineering, applied to building one feature.* +*Context engineering, applied to building one feature — the harness’s short-term memory.* The smallest complete unit of work is a feature: take an idea, turn it into code that works. Spec-Driven Development (SDD) is what happens when you treat that as @@ -9,7 +9,7 @@ a context-engineering problem rather than a typing problem. The question from Chapter 1 — *what is the right context, and how does it reach the window at the right moment?* — has a concrete answer here, and Context Specs ships it as a handful of Agent Skills. **This layer needs nothing else in this -book.** You can `npx skills add` it today and use it by hand on any project, with +book.** You can link or copy these skills into any project today and drive them by hand, with or without the harness in later chapters. ## The problem SDD solves @@ -35,19 +35,17 @@ project's accumulated knowledge: how this codebase is layered, how it tests new routes, which patterns to reach for and which to avoid. Re-explaining that every session is exactly the context decay Chapter 1 warned about. -An **Expert** externalizes it. You create one from your own documentation — -framework docs, an internal library guide, architecture notes — with -[`/expert-sdd-creator`](../skills/sdd/expert-sdd-creator/SKILL.md), and -it generates a complete, progressively-disclosed knowledge module: +An **Expert** externalizes it as a progressively-disclosed knowledge module. +Your project's own Expert — its long-term memory — is seeded as a skeleton by +`/env-init` and grows from there (Chapter 4); you can add further Experts for +external domains (an internal library, a framework) the same way, as +`expert-{name}/` skills alongside it: ``` -expert-{name}/ -├── SKILL.md # high-level pointer, read first -├── references/ # dense knowledge, read only when relevant -│ ├── {topic}.md -│ └── signal-workflow.md -└── scripts/ - └── run_signal.sh +expert/ # (or expert-{name}/ for an outside domain) +├── SKILL.md # high-level index + routing table, read first +└── references/ # dense knowledge, one topic per file, read on demand + └── {prefix}-{topic}.md ``` The Expert is the menu from Chapter 1 made concrete: a short `SKILL.md` the agent @@ -158,7 +156,7 @@ orchestrator's window lean and every commit reviewable. The feedback loop runs **per slice**, not just at the end — the agent knows whether it's on track as it goes, not after. -## What you have at the end of Layer 1 +## What you have at the end of this chapter A repeatable way to take one feature from idea to working code while keeping the agent's window full of exactly the right context and nothing else: knowledge diff --git a/docs/3-the-agent-harness.md b/docs/3-the-agent-harness.md index d69f829..633ff44 100644 --- a/docs/3-the-agent-harness.md +++ b/docs/3-the-agent-harness.md @@ -1,20 +1,57 @@ # Chapter 3 — The agent harness -*Layer 2 — the project runs the SDD loop for you.* +*The system: deterministic code driving probabilistic code to a guaranteed output.* Here is the whole promise of this chapter in one sequence: -> You describe a feature to [`/intent`](../skills/human-loop/intent/SKILL.md) and -> confirm it. Then you walk away. The project plans the feature, validates the -> plan, implements it, runs its checks, opens a pull request, answers the -> reviewer's comments — and hands you back a PR that's ready to merge. You come -> back to finished work you never typed. +> You describe a feature to your project's `/intent` and confirm it. Then you +> walk away. The project plans the feature, validates the plan, implements it, +> runs its checks, opens a pull request, answers the reviewer's comments — and +> hands you back a PR that's ready to merge. You come back to finished work you +> never typed. -That's the harness. It takes the Layer 1 loop — `/spec-planning` → +That's the harness. It takes the Chapter 2 loop — `/spec-planning` → `/spec-validate` → `/implement-mainspec` — that you used to drive by hand, and -**runs it autonomously**, end to end, while you do something else. Everything in -this chapter is in service of that one capability, and of the second question it -immediately raises: *why would you trust a machine to do this unattended?* +**runs it autonomously**, end to end, while you do something else. + +Name what this is, because the name is the design: **harness engineering** — +building a system with defined inputs and defined outputs out of deterministic +code and probabilistic code, where the deterministic code invokes the +probabilistic code and controls the flow to a guaranteed, well-defined output. +The input is a PRD with a runnable definition of done. The output is **a PR +that is either ready to merge or STUCK with a diagnosis** — the system never +hands back "maybe." Everything in this chapter is in service of that contract, +and of the question it raises: *why would you trust a machine to do this +unattended?* + +## Two tiers: one harness, N environments + +The harness is not something you install into a project. It's its own repo — +**the harness repo** — that operates on any number of project repos, called +**environments**: + +``` +HARNESS REPO (yours, one) ENVIRONMENT REPOS (your projects, many) + bin/context-specs the CLI AGENTS.md the eager contract + scripts/ the dispatchers .claude/skills/intent/ project-owned /intent + skills/ canonical skills .claude/skills/expert/ long-term memory + state// runtime state scripts/bootstrap-worktree.sh, local-checks.sh + .harness/env this env's dials +``` + +The dividing line is a single test: *could you write it without reading the +project's code?* Yes → it lives in the harness repo, where improving it once +improves every environment. No → it's **Software 3.0**, generated by an LLM +reading that project, committed to that project, evolving with it. + +The two tiers meet through symlinks: `context-specs add ` links the +canonical skills into an environment's `.claude/skills/` (gitignored — they're +the harness's, not the project's). Two skills are deliberately *not* linked, +because they are the project's two owned levers: **/intent** (installed as a +committed copy — how well a project expresses intent is one of the biggest +levers it has) and **the Expert** (the long-term memory, Chapter 4). The setup +itself demonstrates the discipline: the CLI does the deterministic half, then +the `/env-init` skill reads the project and generates the Software 3.0 half. ## The autonomous loop @@ -43,24 +80,24 @@ so it can't argue forever, and if any step genuinely can't make progress, the harness stops and hands you the problem rather than faking success — more on both below. -### `/intent` — the one place a human starts +### `/intent` — the goal, pinned down -The loop begins with the single human-attentive skill in the chain. -[`/intent`](../skills/human-loop/intent/SKILL.md) turns an open-ended idea into two -coupled artifacts: +The loop begins with the single human-attentive skill in the chain. `/intent` +turns an open-ended idea into two coupled artifacts: - `prds//prd.md` — the prose: **why** this exists and **what** "done" means; - `prds//run-prd-test.sh` — the executable: **how you'll know** it's done. It exits 0 when the feature is built. -The runner is the load-bearing idea. Prose drifts and "done" becomes an -argument; an exit code doesn't. Before `/intent` commits anything, it runs the -script against today's unbuilt code and confirms it fails **for the right -reason** — because the behavior is genuinely absent, not because of a typo or a -missing dependency. That's the empirical proof that the test actually -corresponds to the intent. (`/intent` is also where the human loop in Chapter 5 -plugs in — but you can use it perfectly well on its own right now.) +The runner is the load-bearing idea, and it's what makes the harness +**goal-based**: the runner *is* the goal, and the loop keeps invoking the model +until the goal is met or the retry caps call it honestly unreachable. Prose +drifts and "done" becomes an argument; an exit code doesn't. Before `/intent` +commits anything, it runs the script against today's unbuilt code and confirms +it fails **for the right reason** — because the behavior is genuinely absent, +not because of a typo or a missing dependency. That's the empirical proof that +the test actually corresponds to the intent. Once confirmed, the PRD lands on a branch and the harness takes over. @@ -73,11 +110,12 @@ state of every feature is observable from two things: the files on disk and the branches in git. A small bash script — the **dispatcher** -([`poll-and-dispatch.sh`](../skills/harness/harness-init/assets/poll-and-dispatch.sh)) -— wakes up periodically, reads that state fresh, and decides the single next step -for each active feature. Its core is an `if/elif` chain: *planning output absent? -run planning. Present but validation absent? run validate.* The chain **is** the -state machine; the artifacts on disk **are** the state. +([`scripts/poll-and-dispatch.sh`](../scripts/poll-and-dispatch.sh)) — wakes up +periodically, takes an environment as its argument, reads that environment's +state fresh, and decides the single next step for each active feature. Its core +is an `if/elif` chain: *planning output absent? run planning. Present but +validation absent? run validate.* The chain **is** the state machine; the +artifacts on disk **are** the state. Three consequences fall out of that design, and together they're why the machine is trustworthy: @@ -97,6 +135,12 @@ is trustworthy: mechanical. That's what makes "what will it do next?" answerable just by looking at disk — no model in the loop to second-guess. +And one consequence for your working tree, because it's the one developers ask +about first: **the harness never touches your checkout.** It operates on your +clone only through git *refs* — fetching, pushing, claiming branches — and does +all its work in *sibling worktrees* (`-harness-`) it creates and +tears down itself. Your uncommitted work is structurally out of its reach. + These properties have names and precise statements. When you want the rigorous version — what holds under concurrency, what each layer guarantees, how recovery composes — read the **[design invariants](./invariants.md)**. This chapter gives @@ -141,8 +185,11 @@ PRD that left something out — and correct that first. Because if the context t caused the failure stays wrong, the same class of failure comes back the next time a feature touches that area. -STUCK is the harness being honest about the boundary of what it can do alone — -and routing the rest to the one place judgment lives. +STUCK is the other half of the output contract. Ready-to-merge and STUCK are +both *finished* states — the system completed its run and told you the truth +about which one you got. And the ratio between them is your metric: every STUCK +names the context to improve, and Chapter 4 is about how those improvements +compound. ## The branch namespace is the work queue @@ -164,26 +211,36 @@ coordination daemon; git refs are the lock. By default each developer's harness watches only their own `prd//*` queue, so your harness is your personal assistant, not a shared teammate. -## It runs wherever you do +## Running it: the CLI -The skills, the artifacts, and the branch conventions are portable. The only -thing that's environment-specific is the **trigger** — what wakes the dispatcher. -That's a one-line choice, and changing it changes nothing else: +The deterministic half of the system extends one layer up — a small CLI in the +harness repo schedules the dispatcher: -``` -/loop → CronCreate → Agent SDK → GitHub Actions / server -single dev, single dev, programmatic team-scale, runs without -visible background glue anyone's laptop on +```bash +npx context-specs init my-harness # create your harness repo (once) +context-specs add ~/code/myapp # register an environment, link the skills +# in ~/code/myapp: claude → /env-init (the Software 3.0 half, then merge its PR) +context-specs start # walk away ``` -The recommended start is the simplest thing that exists: open a Claude Code -session and run `/loop 5m /poll-and-dispatch`. That's it — the outer loop is a -session you already have open. When a team outgrows local laptops, they move the -*trigger* to a server and keep everything else. It's an upgrade path, not a -rewrite. (Setting all of this up is itself a guided skill — -[`/harness-init`](../skills/harness/harness-init/SKILL.md) — which stands -up the dispatcher, the config, the verification gate, and the worktree -provisioning, explaining each piece as it goes.) +`start` runs one background supervisor per environment — a build loop and a +memory loop (Chapter 4). The scheduling protocol is nothing more than the +dispatcher's exit code: **0** means idle (sleep the interval, default 5 +minutes), **10** means "work advanced" (re-invoke immediately). That second case +matters: a claimed PRD marches through planning → validate → implement at +machine speed, while idle polling stays cheap. Errors back off exponentially. A +STUCK feature reports idle — a stuck environment never hot-loops. + +Because each environment gets its own supervisor, own lock, and own state, +**working on multiple projects at once is the default**, not a mode. +`context-specs status` shows every environment's features and phases in one +table; `context-specs run ` does a single foreground pass when you'd rather +watch; `logs -f` follows the loop; `doctor` checks the wiring. + +The trigger is still the portable part: the same dispatcher that a laptop +supervisor invokes can be invoked by cron or a server runner. When a team +outgrows local laptops, they move the *scheduler* and keep everything else. +It's an upgrade path, not a rewrite. --- diff --git a/docs/4-continuous-improvement.md b/docs/4-continuous-improvement.md index 30e96cf..6ff0793 100644 --- a/docs/4-continuous-improvement.md +++ b/docs/4-continuous-improvement.md @@ -1,6 +1,6 @@ # Chapter 4 — Continuous improvement -*Layer 2 — the harness gets better every merge.* +*The flywheel — the harness gets better every merge.* A harness that only built features would be a fast worker with no memory. Each feature would start from the same blank slate; the same hard-won lesson — *this @@ -123,7 +123,7 @@ Inside the Expert, the files are kept small and topic-focused, cross-linked with and follows links to the rest — progressive disclosure, so consulting memory never means loading all of it. -## What you have at the end of Layer 2 +## What you have at the end of this chapter A project that not only builds features unattended, but gets measurably easier to build the next feature in — because every merge that taught something durable put diff --git a/docs/5-the-human-loop.md b/docs/5-the-human-loop.md index a772030..bbd21d0 100644 --- a/docs/5-the-human-loop.md +++ b/docs/5-the-human-loop.md @@ -1,6 +1,6 @@ # Chapter 5 — The human loop -*Layer 3 — freed from typing, you improve the harness.* +*Freed from typing, you improve the harness.* Chapters 3 and 4 built a machine that builds and remembers. This chapter is about what you do now that it does. The honest answer is: **the most important part** — diff --git a/docs/README.md b/docs/README.md index bfacac4..72350b5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -10,51 +10,69 @@ agents, stops looking like a codebase you type into and starts looking like a ## The through-line -One idea runs under everything here: **the right context at the right time.** -What enters an agent's context window is the biggest lever you have. Context -Specs is that lever, pulled at three levels — each one building on the one -before it: +This project is **harness engineering in practice**. Harness engineering is +building a system — defined inputs, defined outputs — out of deterministic code +and probabilistic code, where the deterministic code invokes the probabilistic +code and controls the flow all the way to a guaranteed, well-defined output. + +Here the input is a PRD with a runnable definition of done, and the output is +**a pull request that is either ready to merge or STUCK with a diagnosis** — +never "maybe." That output is also the system's feedback signal: every STUCK +and every review finding points at a piece of context to improve, and context +engineering — the right context at the right time — is the lever that moves the +ready-to-merge ratio up. ``` -Context engineering the idea: an agent choosing what enters its window +Context engineering the lever: what enters an agent's window decides everything │ ▼ -Spec-Driven Development Layer 1 — the idea, applied to building one feature - │ +Spec-Driven Development the harness's short-term memory — plan one feature + │ outside the window, feed it back a slice at a time ▼ -The agent harness Layer 2 — the project runs that loop for you, and - │ gets better every merge +The agent harness the system: deterministic code driving probabilistic + │ code from PRD to a guaranteed output (PR or STUCK) ▼ -The human loop Layer 3 — freed from typing, you improve the harness +Long-term memory the flywheel: the project learns every merge, and + │ long-term memory informs every future plan + ▼ +The human loop the goals and the judgment: intent in, evaluation out │ ▼ A mindset shift your project has become a harness; your job is context ``` -Each layer is usable without the ones above it. Spec-Driven Development needs no -harness. The harness needs no human-loop discipline to run. The value compounds -as you climb — but you can stop on any rung. +Two memory systems run through everything. The **Expert** (plus `AGENTS.md`) is +the project's *long-term* memory; the specs and slices are *short-term* memory — +the plan for one feature, informed by the long-term memory every time it's +written. Improve the long-term memory and every future feature plans better. +It's written back on two rhythms: **Reflection** in the hot path (after each +slice) and **/learn** off the hot path (after each merge — the system +consolidating what it learned while nothing is running, the way agents like +OpenClaw "dream"). + +And the whole thing is **goal-based**: `/intent` pins the goal down as a +runnable test, and the harness keeps invoking the model until the goal is met — +or the retry caps turn honest failure into STUCK. ## The chapters 1. **[Context engineering](./1-context-engineering.md)** — what it actually is, and why the context window is the scarce resource everything else is fighting over. -2. **[Spec-Driven Development](./2-spec-driven-development.md)** *(Layer 1)* — how - Context Specs applies context engineering to a single feature: experts, specs, - temporal slicing, reflection, consensus validation. The foundation, usable on its - own. -3. **[The agent harness](./3-the-agent-harness.md)** *(Layer 2)* — file a PRD, - walk away, come back to a finished PR. The autonomous loop, and why you can - trust a machine to run it unattended. -4. **[Continuous improvement](./4-continuous-improvement.md)** *(Layer 2)* — how - the harness gets better every merge: long-term memory, the four destinations - for a learned fact, and lints the agent cannot ship past. -5. **[The human loop](./5-the-human-loop.md)** *(Layer 3)* — once the machine does - the typing, what's left is the part only you can do: Understanding → Intent → +2. **[Spec-Driven Development](./2-spec-driven-development.md)** — the harness's + short-term memory: experts, specs, temporal slicing, reflection, consensus + validation. Usable on its own, no harness needed. +3. **[The agent harness](./3-the-agent-harness.md)** — the system itself: one + harness repo driving N environments, a deterministic dispatcher, and why you + can trust a machine to run it unattended. +4. **[Continuous improvement](./4-continuous-improvement.md)** — the flywheel: + long-term memory, the destinations for a learned fact, and lints the agent + cannot ship past. +5. **[The human loop](./5-the-human-loop.md)** — once the machine does the + typing, what's left is the part only you can do: Understanding → Intent → Evaluate. -6. **[The mindset shift](./6-the-mindset-shift.md)** — the payoff. Your project is - a harness now. Here's how the way you work changes. +6. **[The mindset shift](./6-the-mindset-shift.md)** — the payoff. Your project + is a harness now. Here's how the way you work changes. ### Reference @@ -65,7 +83,8 @@ as you climb — but you can stop on any rung. ## Where the code lives -Everything described here ships as Agent Skills under -[`skills/`](../skills/). The chapters point at the specific -skill, script, or reference file that implements each idea, so you can read the -story and then go read the source. +The deterministic half is the [`context-specs` CLI](../bin/) and the dispatcher +scripts under [`scripts/`](../scripts/); the probabilistic half ships as Agent +Skills under [`skills/`](../skills/). The chapters point at the specific skill, +script, or reference file that implements each idea, so you can read the story +and then go read the source. diff --git a/docs/invariants.md b/docs/invariants.md index 367ec52..c9d2e1f 100644 --- a/docs/invariants.md +++ b/docs/invariants.md @@ -24,7 +24,7 @@ break. 3. [Worktree ↔ branch is 1:1 per node](#invariant-3--worktree--branch-is-11-per-node) 4. [Skill idempotency via write-then-touch](#invariant-4--skill-idempotency-via-write-then-touch) 5. [Dispatcher discipline](#invariant-5--dispatcher-discipline) - 6. [Human's working tree is sandboxed](#invariant-6--humans-working-tree-is-sandboxed) + 6. [The developer's working tree is sandboxed](#invariant-6--the-developers-working-tree-is-sandboxed) 7. [Cross-node safety](#invariant-7--cross-node-safety) 8. [Verification is non-bypassable](#invariant-8--verification-is-non-bypassable) 9. [Forward-only state machine](#invariant-9--forward-only-state-machine) @@ -68,9 +68,10 @@ An **invariant** here is a property the system must maintain regardless of crash **How it's enforced.** -- Counters live in `.harness/` files. -- Sentinels are committed to the branch. -- PR state is observed via `gh pr view`. +- Retry counters and runtime sentinels live in the harness repo's + `state//` files (per-environment, gitignored, safely wipeable). +- Pipeline sentinels are committed to the feature branch. +- PR state is observed via `gh pr view` (run with the environment as cwd). - The dispatcher reads everything fresh at the start of every tick. ### Invariant 2 — Branch namespace IS the work registry @@ -97,7 +98,8 @@ An **invariant** here is a property the system must maintain regardless of crash **How it's enforced.** -- Worktree paths are per-feature: `${WORKTREE_BASE}-${feature}`. +- Worktree paths are per-feature siblings of the environment's clone: + `-harness-` (derived from the environment's path). - The advance loop verifies `git rev-parse --abbrev-ref HEAD` matches the iterated branch before acting; skip if not. - The `MAX_WORKTREES` env var caps concurrent worktrees; >1 = parallelism opt-in. @@ -119,22 +121,24 @@ An **invariant** here is a property the system must maintain regardless of crash ### Invariant 5 — Dispatcher discipline -**Statement.** The dispatcher contains zero LLM calls. It executes at most one skill step per branch per tick. Skill invocations (`claude -p`) within a tick are synchronous and sequential. +**Statement.** The dispatcher contains zero LLM calls. It executes at most one skill step per branch per tick. Skill invocations (`claude -p`) within a tick are synchronous and sequential. Its entire scheduling interface is its exit code: `0` = idle, `10` = advanced (the supervisor re-invokes immediately — a *drain*, not a second step within the tick), anything else = error. -**Why it matters.** A dispatcher with LLM in the decision loop is non-reproducible and inflates context cost. Multi-step-per-tick makes "what will the next action be?" unanswerable from disk state. +**Why it matters.** A dispatcher with LLM in the decision loop is non-reproducible and inflates context cost. Multi-step-per-tick makes "what will the next action be?" unanswerable from disk state. The exit-code protocol keeps the supervisor equally deterministic — it holds no opinion about the work, only about *when* to ask again. -**What breaks if violated.** Embedding `claude -p` in the dispatcher's decision logic makes the dispatcher itself a cost surface. Allowing skill chaining within a tick makes the state machine harder to debug. +**What breaks if violated.** Embedding `claude -p` in the dispatcher's decision logic makes the dispatcher itself a cost surface. Allowing skill chaining within a tick makes the state machine harder to debug. Exiting `10` from an error path (or from a STUCK-only tick) makes the supervisor hot-loop a broken environment. **How it's enforced.** - The dispatcher script is pure bash + `git` + `gh`. No `claude -p` outside the skill-invocation positions. - The if/elif chain in the advance loop fires at most one branch per iteration. - `claude -p` invocations are blocking; no `&` backgrounding. -- `flock -n` at the top of the script prevents overlapping dispatcher runs on the same node. +- `flock -n` on the per-environment lock (`state//tick.lock`) prevents overlapping ticks for the same environment. The lock is per-env, not on the script — the script is shared by every environment, and environments must not serialize against each other. +- A `TRANSITIONS` counter (bumped by `run_claude`, the PRD claim, the PR open, the auto-fix commit, and the `.prd-passed` sentinel) drives the final exit; STUCK paths never bump it, so a stuck environment reports idle. +- The build loop and the memory loop (`learn-dispatch.sh`) are two independent loops with separate locks and separate worktrees; they coordinate only through git. -### Invariant 6 — Human's working tree is sandboxed +### Invariant 6 — The developer's working tree is sandboxed -**Statement.** The harness never touches the human's checkout. Worktrees live at separate filesystem paths. `/intent` is the sole carve-out, justified by being a synchronous conversational skill where the human is attentive. +**Statement.** The harness never touches the developer's checked-out files. It operates on the environment's clone only through *ref* operations (`git -C fetch/push/for-each-ref/cat-file`) and through *sibling worktrees* it creates and tears down itself. `/intent` is the sole carve-out, justified by being a synchronous conversational skill the developer runs themselves, attentively, in their own checkout. **Why it matters.** This is the trust invariant. If the harness ever stomps WIP, social trust in the design collapses regardless of how clean the technical model is. @@ -142,11 +146,13 @@ An **invariant** here is a property the system must maintain regardless of crash **How it's enforced.** -- Worktree paths are `${WORKTREE_BASE}-${feature}`, separate from the human's `.git`-containing checkout. -- The dispatcher only runs in worktrees, never in the human's checkout. -- `/intent` is invoked manually in the human's checkout by the human; no automation triggers it. +- The dispatcher lives in the **harness repo**, not the environment — there is no harness code inside the project to run "in place," and its cwd is never the developer's checkout. +- Every environment operation is either a ref op (fetch, push, cat-file, for-each-ref — none touch a working tree) or scoped to a `-harness-*` sibling worktree (`git -C "$wt"`, `cd "$wt"`). The wipe/reset/clean commands run only inside per-feature worktrees. +- The one filesystem write into the environment's checkout is the gitignored `.claude/` symlinks — created by `context-specs add`/`link`, which the developer runs themselves. +- `bootstrap-worktree.sh` copies secrets FROM the developer's checkout INTO worktrees — never the reverse, never deletes. +- Worktree creation does add refs to the shared `.git` (a local `feature/` branch appears in the developer's `git branch` output, and is deleted again at cleanup) — ref noise, by design never working-tree changes. -In server mode this invariant becomes trivial (no human-checkout on the server). It remains stated because the invariants are mode-independent. +In server mode this invariant becomes trivial (no developer checkout on the server — the "clone" is the harness's own). It remains stated because the invariants are mode-independent. ### Invariant 7 — Cross-node safety @@ -199,12 +205,12 @@ The invariants above are stated mode-independently. The OS-level enforcement mec | Invariant | Local enforcement | Server enforcement | Notes | |---|---|---|---| -| 1 — State on disk | `.harness/` files + committed sentinels | Same, on the runner's checkout | Identical | +| 1 — State on disk | harness repo `state//` + committed sentinels | Same, on the runner's checkout | Identical | | 2 — Branch as registry | Atomic git ref ops on origin | Same | Same primitive; lower contention server-side | | 3 — Worktree ↔ branch 1:1 | `git worktree add` + HEAD guard | Each runner job = fresh checkout; implicit 1:1 | Server gets it "for free" via job ephemerality | | 4 — Skill idempotency | Write-then-touch in skill code | Same | Identical | -| 5 — Dispatcher discipline | Pure bash + `flock -n` | GH Actions workflow + `concurrency:` key per branch | `flock` and `concurrency:` serve the same role | -| 6 — Human sandbox | Worktree at separate path | N/A — no human on server | Becomes trivial server-side; remains stated for portability | +| 5 — Dispatcher discipline | Pure bash + per-env `flock -n` + exit-code protocol | GH Actions workflow + `concurrency:` key per branch | `flock` and `concurrency:` serve the same role | +| 6 — Developer sandbox | Ref-only ops on the clone + sibling worktrees | N/A — no developer checkout on server | Becomes trivial server-side; remains stated for portability | | 7 — Cross-node safety | Atomic ops + ls-remote checks | Same; usually N=1 on server | Same primitives, lower contention | | 8 — Verification non-bypass | Dispatcher invokes runner | Workflow step invokes runner | Identical | | 9 — Forward-only state | Skills don't un-touch | Same | Identical | @@ -212,7 +218,7 @@ The invariants above are stated mode-independently. The OS-level enforcement mec A few mode-specific notes worth carrying with you: - **`/intent` always runs locally.** It's conversational; needs a human at a terminal. Server picks up after the `prd/` branch is pushed. Universal, not a mode difference. -- **Counter location.** Per-node `.harness/` files. On server (N=1) this is effectively per-branch since one server owns each branch's lifetime. On local with multi-node handoff, counters reset on the new machine — see § 4. +- **Counter location.** Per-harness `state//` files. On server (N=1) this is effectively per-branch since one server owns each branch's lifetime. On local with multi-node handoff, counters reset on the new machine — see § 4. - **`flock` ↔ `concurrency:`.** Same role: serialize ticks against the same work unit. - **Wipe at tick start ↔ fresh checkout per run.** Same semantics; uncommitted state has zero lifetime across runs in either mode. - **Cross-node primitives cost nothing when N=1.** Leave them in regardless of mode — they're the upgrade path. @@ -247,18 +253,18 @@ Five decisions in the design are choices, not invariants. Each can be flipped pe **When to flip.** Team projects with multiple concurrent features and surplus disk + CI capacity. -### Counter location — per-node `.harness/` (chosen) vs per-branch committed +### Counter location — per-harness `state//` (chosen) vs per-branch committed **Alternative.** Counters committed to the feature branch itself (one commit per round). -**Why per-node.** Works for both pure-local single-dev and pure-server N=1. The handoff case (laptop dies mid-PR-debate, resume on desktop) is the only place per-node hurts, and the failure mode is "extra LLM rounds," not "wrong behavior." +**Why per-harness.** Works for both pure-local single-dev and pure-server N=1. The handoff case (laptop dies mid-PR-debate, resume on desktop) is the only place per-node hurts, and the failure mode is "extra LLM rounds," not "wrong behavior." **When to flip.** Shared-pool concurrency (multiple harnesses cooperating on the same branch) or scenarios where machine handoff is common and the cost of extra rounds matters. ### `feature/*` ownership contract — PRD-file-committed (chosen) vs loose match **Alternative (loose).** Pick up any `feature/*` on origin. -**Alternative (local file).** Record claims in `.harness/claimed`. +**Alternative (local file).** Record claims in a local state file. **Why PRD-file-committed.** Stateless, cross-node-safe, no per-node tracking. Also gives a clean opt-in mechanism for non-`/intent` work — commit a PRD stub on a branch and the harness picks it up. @@ -298,19 +304,21 @@ Each walkthrough names the failure, traces what happens tick by tick, and points ### Two ticks fire concurrently -**Setup.** `/loop 5m /poll-and-dispatch` and `CronCreate` both configured by mistake; both fire at the same minute. +**Setup.** The `context-specs start` supervisor fires a tick at the same moment a human runs `context-specs run` by hand for the same environment. **Trace.** -1. Tick A acquires flock first. -2. Tick B's `flock -n` fails; script exits 0. -3. Tick A proceeds normally. +1. Tick A acquires the per-env `flock` on `state//tick.lock` first. +2. Tick B's `flock -n` fails; script exits 0 (idle). +3. Tick A proceeds normally. (A tick for a *different* environment holds a + different lock file and is unaffected — environments never serialize + against each other.) **Invariants composed.** 5. ### Two harnesses race on the same PRD -**Setup.** Alice runs `/loop` on her laptop and also has an open Claude Code session on her desktop. Both see `prd/alice/foo`. +**Setup.** Alice runs `context-specs start` on her laptop and forgot a running supervisor on her desktop. Both see `prd/alice/foo`. **Trace.** @@ -349,12 +357,12 @@ Each walkthrough names the failure, traces what happens tick by tick, and points ### Human laptop dies mid-PR-review -**Setup.** Alice's laptop is at `feedback-rounds-foo=3` (two away from STUCK cap of 5). Laptop is bricked. Alice clones fresh on her desktop and runs `/loop`. +**Setup.** Alice's laptop is at `feedback-rounds-foo=3` (two away from STUCK cap of 5). Laptop is bricked. Alice clones her harness repo and the project fresh on her desktop, runs `context-specs add` + `start`. **Tick fires on desktop.** 1. Re-attach: `feature/foo` exists, has PRD, no local worktree — `git worktree add` creates it. -2. Advance: `.harness/feedback-rounds-foo` doesn't exist on the new machine; effective counter is 0. +2. Advance: `state//feedback-rounds-foo` doesn't exist on the new machine; effective counter is 0. 3. If a reviewer finding is unresolved, `/address-feedback` is invoked with counter incremented to 1 (not 4). **Result.** Alice gets the full 5 rounds again; extra LLM rounds, never broken correctness. This is the per-node counter limitation called out in § 4. Mitigation if it matters: commit counters to the branch (per-branch alternative). @@ -367,4 +375,4 @@ Each walkthrough names the failure, traces what happens tick by tick, and points - [The documentation story](./README.md) — the narrative these properties underpin, starting from context engineering. - [Chapter 3 — The agent harness](./3-the-agent-harness.md) — the intuition for why the harness is safe; this document is its proof. -- [`poll-and-dispatch.sh`](../skills/harness/harness-init/assets/poll-and-dispatch.sh) — the dispatcher: the canonical realization of these invariants in code. +- [`scripts/poll-and-dispatch.sh`](../scripts/poll-and-dispatch.sh) — the dispatcher: the canonical realization of these invariants in code. From 3b8a51f7c4c197b1f2da804cbaccf9aea4a28ada Mon Sep 17 00:00:00 2001 From: Rico Date: Sun, 5 Jul 2026 13:25:41 -0500 Subject: [PATCH 12/14] Re-link skill symlinks after the per-tick worktree wipe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git clean -fd deletes the (untracked) tier-1 symlinks whenever a feature branch's .gitignore predates the managed block — and bootstrap only runs at worktree creation. Re-linking after every wipe is idempotent and cheap, and guarantees no skill step ever runs skill-less. Found by the end-to-end drain fixture. Co-Authored-By: Claude Fable 5 --- scripts/poll-and-dispatch.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/poll-and-dispatch.sh b/scripts/poll-and-dispatch.sh index b2fd359..c103f1f 100755 --- a/scripts/poll-and-dispatch.sh +++ b/scripts/poll-and-dispatch.sh @@ -274,6 +274,13 @@ for feature in ${in_flight[@]+"${in_flight[@]}"}; do && git clean -fd --quiet \ && git reset --hard "origin/$branch" --quiet ) + # Re-link the tier-1 skill symlinks after the wipe. They're untracked, and on + # a branch whose .gitignore predates the managed block (e.g. a PRD filed + # before env-init merged), `git clean -fd` just deleted them — and bootstrap + # only runs at worktree creation. Idempotent and cheap; never let a skill run + # skill-less. + "$CONTEXT_SPECS_HOME/bin/context-specs" link "$wt" >/dev/null 2>&1 || true + # State machine: walk forward by exactly one step. Sentinel files gate each # transition. Every step has a bounded retry; at cap, signal_stuck posts to the # PR (opening one as a draft if necessary) with the step, the session log, an From e04e9b5314936459979c34b33ad8af703d464ce8 Mon Sep 17 00:00:00 2001 From: Rico Date: Sun, 5 Jul 2026 18:41:14 -0500 Subject: [PATCH 13/14] =?UTF-8?q?status:=20apply=20the=20dispatcher's=20li?= =?UTF-8?q?veness=20gate=20=E2=80=94=20don't=20list=20MERGED/CLOSED=20feat?= =?UTF-8?q?ures?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Branch existence is not liveness: a merged feature keeps its origin branch and committed PRD forever, so status resurrected every finished feature. Mirror the dispatcher's step-1 gate (gh pr view state, run in the env for repo resolution) with the same fail-safe — no PR or transient gh failure counts as live, so pre-PR work is never hidden. Drops the 'no gh calls' property; correctness and consistency with the dispatcher win. Co-Authored-By: Claude Fable 5 --- lib/status.js | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/status.js b/lib/status.js index 57b4f45..cf4cfc1 100644 --- a/lib/status.js +++ b/lib/status.js @@ -2,16 +2,29 @@ // One-shot, deterministic render of the whole harness's state. Everything is // derived from artifacts — committed sentinels on the feature branches, counter // and sentinel files in state//, the pidfile — exactly the "state lives on -// disk + branches" invariant, read instead of written. No gh calls: fast and -// offline; PR-level state is one click away on GitHub. Remote-tracking refs are +// disk + branches" invariant, read instead of written. Remote-tracking refs are // as of the last fetch (a tick fetches every interval); pass --fetch to update // them first. +// +// One gh call per feature is unavoidable: branch existence is NOT liveness. A +// merged feature keeps its origin branch and its committed PRD forever, so +// without the same MERGED/CLOSED gate the dispatcher's step 1 applies, status +// would resurrect every finished feature. Fail-safe mirrors the dispatcher's: +// no PR yet (pre-PR phases) or a transient gh failure → treat as live — never +// silently hide live work. const fs = require('fs'); const path = require('path'); const registry = require('./registry'); const { stateDir, pidFile } = require('./paths'); -const { git, renderTable, isPidAlive } = require('./util'); +const { git, tryRun, renderTable, isPidAlive } = require('./util'); + +// The dispatcher's liveness gate, verbatim semantics. gh resolves the repo +// from cwd, so run it in the environment (the ghe() equivalent). +function isLive(envPath, feature) { + const state = tryRun('gh', ['pr', 'view', `feature/${feature}`, '--json', 'state', '--jq', '.state'], { cwd: envPath }); + return state !== 'MERGED' && state !== 'CLOSED'; +} // Phase from committed sentinels, mirroring the dispatcher's if/elif chain. function phaseFor(envPath, feature) { @@ -53,7 +66,8 @@ module.exports = async function status(args) { const refs = git(env.path, ['for-each-ref', '--format=%(refname:lstrip=4)', 'refs/remotes/origin/feature/']) || ''; const features = refs.split('\n').filter(Boolean) - .filter((f) => git(env.path, ['cat-file', '-e', `origin/feature/${f}:prds/${f}/prd.md`]) !== null); + .filter((f) => git(env.path, ['cat-file', '-e', `origin/feature/${f}:prds/${f}/prd.md`]) !== null) + .filter((f) => isLive(env.path, f)); if (!features.length) { rows.push([env.name, '—', 'idle', '', '', sup]); From 0fc57debfd9eec10067e779fc642b7ae21d0fd97 Mon Sep 17 00:00:00 2001 From: Rico Date: Sun, 5 Jul 2026 21:41:37 -0500 Subject: [PATCH 14/14] docs updated --- README.md | 266 ++++++----------------- docs/1-context-engineering.md | 92 -------- docs/2-spec-driven-development.md | 180 --------------- docs/3-the-agent-harness.md | 256 ---------------------- docs/4-continuous-improvement.md | 145 ------------ docs/5-the-human-loop.md | 185 ---------------- docs/6-the-mindset-shift.md | 85 -------- docs/README.md | 135 +++++------- docs/concepts/context-engineering.md | 67 ++++++ docs/concepts/continuous-improvement.md | 84 +++++++ docs/concepts/harness-engineering.md | 76 +++++++ docs/concepts/long-term-memory.md | 131 +++++++++++ docs/concepts/output-contract.md | 90 ++++++++ docs/concepts/spec-driven-development.md | 114 ++++++++++ docs/concepts/the-dispatcher.md | 105 +++++++++ docs/concepts/the-human-loop.md | 128 +++++++++++ docs/concepts/two-tier-architecture.md | 77 +++++++ docs/how-to/add-an-environment.md | 55 +++++ docs/how-to/create-a-harness.md | 37 ++++ docs/how-to/evaluate-a-pr.md | 57 +++++ docs/how-to/express-intent.md | 58 +++++ docs/how-to/improve-from-traces.md | 62 ++++++ docs/how-to/initialize-a-project.md | 41 ++++ docs/how-to/run-the-harness.md | 64 ++++++ docs/how-to/unstick-a-feature.md | 49 +++++ docs/overview.md | 93 ++++++++ docs/reference/cli.md | 55 +++++ docs/{ => reference}/invariants.md | 10 +- docs/reference/skills.md | 59 +++++ docs/reference/state-and-branches.md | 70 ++++++ 30 files changed, 1697 insertions(+), 1229 deletions(-) delete mode 100644 docs/1-context-engineering.md delete mode 100644 docs/2-spec-driven-development.md delete mode 100644 docs/3-the-agent-harness.md delete mode 100644 docs/4-continuous-improvement.md delete mode 100644 docs/5-the-human-loop.md delete mode 100644 docs/6-the-mindset-shift.md create mode 100644 docs/concepts/context-engineering.md create mode 100644 docs/concepts/continuous-improvement.md create mode 100644 docs/concepts/harness-engineering.md create mode 100644 docs/concepts/long-term-memory.md create mode 100644 docs/concepts/output-contract.md create mode 100644 docs/concepts/spec-driven-development.md create mode 100644 docs/concepts/the-dispatcher.md create mode 100644 docs/concepts/the-human-loop.md create mode 100644 docs/concepts/two-tier-architecture.md create mode 100644 docs/how-to/add-an-environment.md create mode 100644 docs/how-to/create-a-harness.md create mode 100644 docs/how-to/evaluate-a-pr.md create mode 100644 docs/how-to/express-intent.md create mode 100644 docs/how-to/improve-from-traces.md create mode 100644 docs/how-to/initialize-a-project.md create mode 100644 docs/how-to/run-the-harness.md create mode 100644 docs/how-to/unstick-a-feature.md create mode 100644 docs/overview.md create mode 100644 docs/reference/cli.md rename docs/{ => reference}/invariants.md (97%) create mode 100644 docs/reference/skills.md create mode 100644 docs/reference/state-and-branches.md diff --git a/README.md b/README.md index 8345352..2df84b2 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,53 @@ # Context Specs -**Harness engineering in practice.** +**Applied harness engineering.** -Harness engineering is building a system — defined inputs, defined outputs — -out of deterministic code and probabilistic code, where the deterministic code -invokes the probabilistic code and controls the flow all the way to a -guaranteed, well-defined output. -*([What is Harness Engineering?](https://www.linkedin.com/pulse/what-harness-engineering-rico-romero-vb7fc/))* +*Harness engineering is building a system — defined inputs, defined outputs — out of +deterministic code and probabilistic code, where the deterministic code invokes the +probabilistic code and controls the flow all the way to a guaranteed, well-defined +output.* -Context Specs is that system for building software. The **input** is a PRD with -a runnable definition of done. The **output** is a pull request that is either -**ready to merge** or **STUCK with a diagnosis** — never "maybe." In between: a -deterministic dispatcher that plans, validates, implements, verifies, and -answers the reviewer by driving fresh coding-agent processes, one bounded step -at a time. What's left for you is the judgment a model can't supply — -understanding the problem, deciding what's worth building, and telling whether -what came back is right. +Context Specs is that system for coding — **autonomous** and **goal-based**. You +express intent (your goal); the harness runs on its own; you always get back a pull +request (your guaranteed output) — either **ready to merge**, or **STUCK with a +diagnosis** of what blocked it. -The output is also your feedback signal. Every STUCK and every review finding -points at a piece of *context* to improve — the project's long-term memory, its -contract, its lints. Improve those and the ready-to-merge ratio climbs: the -system gets better at building your project every time it builds. +## The point isn't one PR — it's the system that produces them -> **New here? Read [the full story](./docs/README.md)** — six short chapters -> that take you from the idea to the mindset shift, in order. +You work at the level of the **system that builds features**, not the individual +feature. That distinction is the whole idea: ---- +- **Fix a piece of code** and you ship that one feature. Nothing else changes; the + next feature starts where the last one did. +- **Fix a context gap** — a thin definition of done, a missing piece of long-term + memory, an environment the agent couldn't navigate — and *every future feature* + gets better. You fixed a class of failure, not an instance. + +You do both, but context-gap fixes are the main lever, because they compound. As you +pull it, more PRs come back ready-to-merge and fewer come back stuck. + +So the craft shifts. Instead of typing features, you do **context engineering**: set +up environments agents can work in, pin goals to a real definition of done, and grow +the project's long-term memory — the accumulated knowledge that tells the agent how +to plan every feature. Getting that right is what turns AI slop into PRs you can +actually merge. You operate on the harness; the harness operates on the code. + +## One harness, many projects + +You maintain **one** harness repo and point it at any number of project repos. Improve +the harness once and every project inherits it. + +```mermaid +flowchart LR + H["Your harness\n(one repo you tune)"] + H --> A[project A] + H --> B[project B] + H --> C[project C] +``` + +How the two tiers divide, how the deterministic dispatcher drives each project, and +why it's safe to leave running are all in the docs — this README stays deliberately +short. ## Quickstart @@ -37,202 +59,40 @@ cd my-harness # 2 · Register a project as an environment context-specs add ~/code/myapp -# 3 · The Software 3.0 half: generate the project-specific pieces +# 3 · Generate the project-specific pieces, then merge the PR it opens cd ~/code/myapp && claude -> /env-init # AGENTS.md, /intent, the Expert, checks, bootstrap — one PR +> /env-init # AGENTS.md, /intent, the Expert, checks, bootstrap -# 4 · After that PR merges: walk away +# 4 · Describe a feature, then walk away +> /intent # idea → PRD + runnable definition of done +# then, back in your harness repo: context-specs start ``` -From then on you live in a three-beat cycle — **express intent, the harness -builds, you evaluate**: +From there you live in a three-beat cycle — **express intent, the harness builds, you +evaluate**: ```mermaid flowchart LR - Intent["/intent\nyou express intent"] --> Build["build loop\nplans → builds the PR"] - Build --> Eval["/evaluate-pr · /evaluate-sessions\nyou understand it"] - Eval --> Merge["merge"] - Merge --> Learn["learn loop\nupdates memory → PR"] + Intent["/intent\nyou express intent"] --> Build["the harness builds\nplans → PR"] + Build --> Eval["/evaluate-pr\nyou understand & merge"] + Eval --> Learn["the harness learns\nupdates memory"] Learn --> Intent ``` -`context-specs status` shows every environment's features and phases; -`run ` does one foreground pass; `logs -f` follows the loop; -`doctor` checks the wiring. - ---- - -## The architecture: one harness, N environments - -``` -HARNESS REPO (tier 1 — yours, one) ENVIRONMENT REPOS (tier 2 — your projects) - bin/context-specs the CLI AGENTS.md the eager contract - scripts/ the dispatchers .claude/skills/intent/ project-owned /intent - skills/ canonical skills .claude/skills/expert/ long-term memory - state// runtime state scripts/ bootstrap + local checks - .harness/env this env's dials -``` - -The dividing line is one test: **could you write it without reading the -project's code?** Yes → harness repo; improve it once and every environment -benefits. No → it's *Software 3.0* — generated by an agent reading that -project, committed to that project, evolving with it. `context-specs add` -connects the tiers by symlinking the canonical skills into each environment -(gitignored); `/env-init` generates the project-owned half. - -Two artifacts are deliberately project-owned rather than shared, because they -are the two **developer-owned levers**: - -- **`/intent`** — the input side. How well a project turns an idea into a PRD + - runnable definition of done is one of the biggest levers it has; tune the - skill to your project. -- **The Expert** — the memory side. The project's long-term memory, which - informs every future plan. The loops file things into it; you shape it. - -## The system, end to end - -> Describe a feature to `/intent` and confirm it. Walk away. The project plans -> the feature, validates the plan, implements it, runs its checks, opens a pull -> request, answers the reviewer — and hands you back a PR that's ready to merge, -> or an honest STUCK with the diagnosis started. - -```mermaid -flowchart LR - Intent["/intent\n(you, once)"] --> Plan["/spec-planning"] - Plan --> Validate["/spec-validate"] - Validate --> Implement["/implement-mainspec"] - Implement --> Checks["local-checks"] - Checks --> PR[Open PR] - PR --> Review[Reviewer ⇄ /address-feedback] - Review --> Ready[Ready for your review] - Ready --> You([You merge]) -``` - -You can trust a machine to run this unattended because it keeps **no hidden -state**: every feature's state is observable from files on disk and branches in -git. A small deterministic dispatcher — **no LLM in the decision path** — reads -that state each tick and shells out to a fresh `claude -p` process per step, so -no step inherits another's polluted window and crash recovery is free. It never -touches your checkout: it works your repo's *refs* and its own sibling -worktrees. Four layers of verification (pre-commit, slice tests, -`local-checks`, and a runnable `run-prd-test.sh` definition of done) can't be -talked past — and the loop is **goal-based**: the runner *is* the goal, and the -dispatcher keeps invoking the agent until it exits 0 or a bounded retry cap -turns honest failure into STUCK. - -The scheduling is one exit code: a tick that advanced work re-fires -immediately (work drains at machine speed), an idle tick naps the interval, a -stuck feature never hot-loops. That's the whole deterministic half — -[read the invariants](./docs/invariants.md) for the proof it's safe to leave -running. - -→ [Chapter 3 — The agent harness](./docs/3-the-agent-harness.md) - -## Memory: long-term informs short-term - -**SDD is the harness's short-term memory.** `/spec-planning` writes the plan for -one feature — a mainspec plus temporally-ordered slices — to disk, *outside* the -context window, so it can't decay or compact away; the implementer is fed one -slice at a time, the right context at the right time, no human routing needed. - -**The Expert is the long-term memory** — and short-term memory is written *from* -it: every plan is informed by what the project already knows. Improve one shard -of long-term memory and every future feature plans better. It's written back on -two rhythms: - -- **Reflection** — in the hot path. After each slice goes green, the implementer - judges whether what it learned should change the project's memory. High bar; - most slices change nothing. -- **`/learn`** — off the hot path. After each merge, the memory loop reads the - merged diff and routes what's worth keeping into the Expert, `AGENTS.md`, or a - custom lint the agent can't ship past — then raises its own `learn/` PR. - The project consolidating what it learned while nothing is running — the way - agentic systems "dream." - -One write path per rhythm, ground truth only, always behind a human merge — and -the third write path is **you**. The Expert is developer-owned; the loops are -helpers. - -→ [Chapter 2 — Spec-Driven Development](./docs/2-spec-driven-development.md) · -[Chapter 4 — Continuous improvement](./docs/4-continuous-improvement.md) - -## The human loop - -*Once the machine does the typing, what's left is the part only you can do.* - -The governing line is Karpathy's: *you can outsource your thinking, but you -can't outsource your understanding.* The harness took the verifiable work. The -human loop is you, working the unverifiable: whether this is the right thing to -build, whether the abstraction is sound, whether it feels right. - -``` -Understanding ──▶ Intent ──▶ [ the harness builds ] ──▶ Evaluate - /wiki-init /intent /evaluate-pr - /evaluate-sessions -``` - -- **Understanding** (`/wiki-init`) — a Karpathy "LLM Wiki" that builds *your* - model of the problem space, so you arrive at Intent with sharper questions. -- **Intent** (`/intent`) — turn that understanding into a PRD plus a runnable - definition of done: the system's input, and its goal. -- **Evaluate** (`/evaluate-pr` + `/evaluate-sessions`) — walk the change to - build real understanding, *and* read the build trail to find where the - project's context served the agents or failed them. The flywheel: *observe a - trace → capture it as an eval → fix the context → it persists.* - -Your loop's output is the harness's input; the harness's output is your loop's -input. When you evaluate, you don't just approve work — you improve the thing -that produced it. - -→ [Chapter 5 — The human loop](./docs/5-the-human-loop.md) - -## The shift - -Put it together and your project stops being a codebase you type into and -becomes a **harness you tune**. The code is an output of the system; your -attention moves from syntax to context. Three things stay yours: deep -understanding of the problem space, theorizing and expressing intent, and -evaluating outcomes to improve the context so every future feature benefits. - -A codebase you type into is a constant cost. A harness you tune is an -appreciating asset — each feature leaves it a little more capable of building -the next one. - -→ [Chapter 6 — The mindset shift](./docs/6-the-mindset-shift.md) - ---- - -## The pieces - -| Where | Piece | Does | -|---|---|---| -| **CLI** | `init` / `add` / `link` | Create the harness repo; register environments; symlink skills | -| | `start` / `stop` / `run` | Supervise the loops (drain-on-advance) / one foreground pass | -| | `status` / `logs` / `doctor` | Observe every environment; check the wiring | -| **Dispatchers** | `scripts/poll-and-dispatch.sh` | The build loop: PRD → PR, one deterministic step per tick | -| | `scripts/learn-dispatch.sh` | The memory loop: merged diff → `learn/` PR | -| **SDD skills** | `/spec-planning` | PRD → mainspec + temporal slices (short-term memory) | -| | `/spec-validate` | Multi-agent consensus review of the plan | -| | `/implement-mainspec`, `/implement-slice` | Implement slices in order, unit tests + Reflect | -| **Harness skills** | `/env-init` | Guided setup of a project as an environment | -| | `/fix-local-checks` | Honest fixes for a failing pre-PR gate | -| | `/address-feedback` | Triage and answer reviewer findings | -| | `/learn` | Post-merge long-term memory update | -| **Human loop** | `/wiki-init` | Stand up a Karpathy LLM-wiki (Understanding) | -| | `/intent` | Idea → PRD + runnable definition of done (project-owned) | -| | `/evaluate-pr` | Evaluate the change; build understanding | -| | `/evaluate-sessions` | Evaluate the build trail; capture evals | - -*(Only want the spec workflow? It stands alone — symlink or copy the SDD skills -and drive `/spec-planning` → `/spec-validate` → `/implement-mainspec` by hand. -No harness needed.)* +`context-specs status` shows every project's features and phases; `run` does one +foreground pass; `logs -f` follows the loop; `doctor` checks the wiring. ## Documentation -- **[The full story](./docs/README.md)** — the six chapters, read in order. -- **[Design invariants](./docs/invariants.md)** — the properties that make the - harness safe to leave running. +- **[How Context Specs works](./docs/overview.md)** — the narrative tour, start to + finish. +- **[Core concepts](./docs/README.md#core-concepts)** — harness engineering, context + engineering, the dispatcher, memory, continuous improvement, the human loop. +- **[How-to guides](./docs/README.md#how-to-guides)** — set up, run, and improve the + harness. +- **[Design invariants](./docs/reference/invariants.md)** — the proof it's safe to + leave running. ## License diff --git a/docs/1-context-engineering.md b/docs/1-context-engineering.md deleted file mode 100644 index 38121f6..0000000 --- a/docs/1-context-engineering.md +++ /dev/null @@ -1,92 +0,0 @@ -# Chapter 1 — Context engineering - -> The single biggest lever you have when you build with a coding agent is what -> goes **into** — and what stays **out of** — its context window. - -It helps to start with one observation, because everything else in this library -follows from it: an agent is only ever as good as the context it's reasoning -over — the actual set of tokens in its window at the moment it decides. Less the -model in the abstract than the material in front of it right now. - -Everything Context Specs does is in service of getting the right context into -that window at the right time, and keeping everything else out. - -## The window is the scarce resource - -A coding agent doesn't "know" your codebase. At any instant it knows exactly -what's in its context window: the conversation so far, the files it has opened, -the tool output it has seen. That window is finite, and it degrades in ways that -are easy to forget: - -- **Context decay.** In a long session, older messages lose influence. The agent - pays the most attention to what's recent and quietly discounts what came - before — so the careful plan you laid out twenty tool calls ago is no longer - really steering anything. -- **Context pollution.** Left to roam, an agent retrieves context on its own: - it greps, opens files, follows imports. A lot of what it pulls in is - irrelevant, and every irrelevant token crowds out a relevant one. -- **Compaction loss.** When the window fills, the session is summarized to make - room. You don't get to choose what's dropped. Critical details disappear and - the agent "forgets" — not because it's careless, but because the bytes are - gone. - -None of these are quirks of a particular model; they're consequences of working -inside a finite window. And they intensify as a task grows — just when holding a -coherent picture matters most. - -## Context engineering is choosing, not dumping - -The intuitive move is to load everything up front: here's the whole architecture, -every convention, all the relevant files, now go. But that runs straight into the -three problems above — it front-loads the pollution and makes compaction a -near-certainty before the agent has done much of anything. - -**Context engineering is the opposite discipline: the agent dynamically pulls -the context it needs, when it needs it, and the substrate it pulls from is the -filesystem.** Two techniques do most of the work: - -- **Externalize the durable stuff.** Anything that must survive a long session — - the plan, the conventions, the domain knowledge — lives in files on disk, not - in the conversation. Files don't decay and don't get compacted. The agent - re-reads them precisely when they're relevant. -- **Progressive disclosure.** You don't hand the agent dense detail; you hand it - a *pointer* — a short, high-level description with a path. The agent reads the - description first, decides whether it needs more, and only then opens the dense - source. The window stays small and focused, holding just what the current step - requires. - -The filesystem is what makes this possible. A file is a unit of context the -agent can choose to load or ignore. A directory of well-named files is a menu it -can navigate just-in-time. The skill of context engineering is largely the skill -of *organizing that menu* — so the right thing is one obvious read away, and the -wrong thing is never accidentally in the window at all. - -## Why this is the foundation - -This lens carries through the whole library — the same idea, applied at larger -and larger scope: - -- A **spec** is the plan, externalized so it can't decay or compact — and sliced - so the agent only ever loads the piece it's working on. *(Chapter 2.)* -- An **Expert** is curated domain knowledge, pulled on demand instead of - re-explained every session. *(Chapter 2.)* -- The **harness** runs a fresh context window per step, so no step ever inherits - another's pollution — and grows a long-term memory so hard-won context - survives across features. *(Chapters 3 and 4.)* -- The **human loop** is you, doing context engineering deliberately: deciding - what the agents should have known, and putting it where they'll find it. - *(Chapter 5.)* - -It's one lever, pulled at every scale. Each layer is answering the same question: -*at this scope, what is the right context, and how does it reach the window at the -right moment?* - ---- - -The first place that question gets a concrete answer is the oldest and most -familiar unit of work: a single feature. How do you give an agent exactly the -context it needs to build one thing well — and nothing it doesn't? - -That's **Spec-Driven Development**, and it's where we go next. - -→ [Chapter 2 — Spec-Driven Development](./2-spec-driven-development.md) diff --git a/docs/2-spec-driven-development.md b/docs/2-spec-driven-development.md deleted file mode 100644 index 46c685c..0000000 --- a/docs/2-spec-driven-development.md +++ /dev/null @@ -1,180 +0,0 @@ -# Chapter 2 — Spec-Driven Development - -*Context engineering, applied to building one feature — the harness’s short-term memory.* - -The smallest complete unit of work is a feature: take an idea, turn it into code -that works. Spec-Driven Development (SDD) is what happens when you treat that as -a context-engineering problem rather than a typing problem. - -The question from Chapter 1 — *what is the right context, and how does it reach -the window at the right moment?* — has a concrete answer here, and Context Specs -ships it as a handful of Agent Skills. **This layer needs nothing else in this -book.** You can link or copy these skills into any project today and drive them by hand, with -or without the harness in later chapters. - -## The problem SDD solves - -Give an agent "add search to the app" and it does something reasonable: it -greps, opens files to infer your conventions, makes a guess at how you test -things. On a small change that's fine. On a large feature it accumulates — -halfway through, the window is full of half-relevant code the agent retrieved on -its own, the original intent has decayed, and the next compaction is poised to -drop the part it actually needed. - -SDD fixes this by doing the thinking **outside** the context window first, and -persisting it as structured files the agent reads progressively. Two artifacts -carry that externalized thinking — and one mechanism carries the knowledge that -shapes them. - -## The Expert — define knowledge once, use it everywhere - -![Experts](../experts.png) - -Most of what makes a feature "right" isn't in the feature request — it's in your -project's accumulated knowledge: how this codebase is layered, how it tests new -routes, which patterns to reach for and which to avoid. Re-explaining that every -session is exactly the context decay Chapter 1 warned about. - -An **Expert** externalizes it as a progressively-disclosed knowledge module. -Your project's own Expert — its long-term memory — is seeded as a skeleton by -`/env-init` and grows from there (Chapter 4); you can add further Experts for -external domains (an internal library, a framework) the same way, as -`expert-{name}/` skills alongside it: - -``` -expert/ # (or expert-{name}/ for an outside domain) -├── SKILL.md # high-level index + routing table, read first -└── references/ # dense knowledge, one topic per file, read on demand - └── {prefix}-{topic}.md -``` - -The Expert is the menu from Chapter 1 made concrete: a short `SKILL.md` the agent -sees first, pointing into dense `references/` it loads only on demand. Define the -knowledge **once**, and it flows automatically through every phase below — you -never paste it into a prompt again. - -Two properties make Experts more than a docs folder: - -- **Composable, not hardcoded.** Multiple Experts activate for one feature. A - React Expert and a DynamoDB Expert both contribute when you build a full-stack - feature, each curating its slice of the context. Add or remove Experts without - touching any existing skill; organizations layer in private Experts for - internal libraries the same way. -- **It curates before, and sharpens after.** An Expert curates context *before* - you write code; then the **Reflect** step at the end of each slice feeds new - lessons — a fresh pattern, a spec that fought the codebase — back into it, so the - Expert gets a little better every time the project builds. (An Expert can also - ship an optional runtime signal script, but a slice's unit tests are the default - proof it works.) - -## Specs — planning lifted out of the window - -When you run [`/spec-planning`](../skills/sdd/spec-planning/SKILL.md), -the planner researches the actual codebase (grounding the plan in reality, not -guesswork), pulls in any Experts whose triggers match, and writes the plan to -disk as two kinds of file: - -- a **mainspec** (`specs//mainspec.md`) — the complete end state, the - north star you work backward from; -- ordered **slices** (`specs//slices/`) — temporal chunks of intent, - each a coherent unit of work focused on *what* and *why*. - -This is the answer to context decay and compaction loss: the plan lives in files, -so it can't be forgotten or summarized away. After a compaction the agent simply -re-reads the spec and "remembers." - -What goes *into* a spec is itself disciplined context engineering — these are the -practices that make a spec something an agent can execute without guessing: - -- **BEFORE/AFTER with precise file paths** — exact current state vs. desired - state, so there's no ambiguity to resolve by greping. -- **Type contracts first** — define interfaces and schemas up front; sometimes an - entire slice is nothing but types. -- **DO/DON'T counterexamples** — one good example, one bad, with *why* the bad one - fails. -- **Narrative temporal flows** — Mermaid sequence diagrams and flowcharts showing - causality across layers. -- **Forward-looking requirements** — each slice notes what future slices will - need, preventing rework. - -## Temporal slicing — progressive disclosure, structurally - -Why slice by *intent* (what needs to happen) rather than by *component* -(frontend/backend)? Because features have a natural dependency order, and slicing -by intent preserves it. Each slice depends on prior slices and declares contracts -for future ones. - -That ordering does two jobs at once. For the implementer, it's progressive -disclosure made structural: the agent is fed **only the current slice**, never -the whole feature, so its window stays small and focused. For the orchestrator, -the dependencies define the execution order. Every mainspec carries a **Slice -Dependency Map** (a table plus a Mermaid graph), which the orchestrator reads to -implement slices in dependency order, one at a time. - -## Validation — consensus before code - -A spec is a plan, and plans have blind spots. [`/spec-validate`](../skills/sdd/spec-validate/SKILL.md) -hardens it before a line of code is written, in three phases: - -1. **Multi-agent consensus.** Spawn 3+ Opus subagents that independently review - the spec. Agreement is signal — and it's graded, not binary: - - | Consensus | Confidence | Reading | - |-----------|------------|---------| - | 3/3 found | Very high | Real issue — fix it | - | 2/3 found | High | Likely real — should fix | - | 1/3 found | Medium | Could be a false positive — judgment call | - -2. **Expert review.** The relevant Experts validate the spec for domain-specific - anti-patterns, library misuse, and gaps a general reviewer would miss. -3. **Consolidation.** Findings are deduplicated and grouped by consensus; the - impactful ones are applied **in place** to the spec files. Validation sharpens - the plan; it doesn't bounce it back to start over. - -A single reviewer has blind spots; independent reviewers have *different* blind -spots, and consensus scoring turns that into a confidence signal instead of a -coin flip. - -## Implementation — write, verify, reflect - -[`/implement-slice`](../skills/sdd/implement-slice/SKILL.md) implements one slice -in three beats: write the code, verify it with unit tests, then **Reflect**. The -first two are the obvious ones. Reflect is the one that compounds: once the code -is green, the agent loads the Expert, compares what it just learned against what -the project already knows, and — only when there's a real lesson — writes it back -as a new or corrected reference. Where the Expert shapes context *before* -implementation, Reflect updates it *after*, so the curation and the learning are -two halves of the same module. The bar is deliberately high: most slices reflect -nothing. - -[`/implement-mainspec`](../skills/sdd/implement-mainspec/SKILL.md) -orchestrates the whole feature: it reads the Slice Dependency Map and delegates -each slice, in dependency order, to a focused `slice-implementer` subagent — -committing each to the feature branch as it lands. One slice at a time keeps the -orchestrator's window lean and every commit reviewable. - -The feedback loop runs **per slice**, not just at the end — the agent knows -whether it's on track as it goes, not after. - -## What you have at the end of this chapter - -A repeatable way to take one feature from idea to working code while keeping the -agent's window full of exactly the right context and nothing else: knowledge -defined once and pulled on demand, planning externalized and disclosed -progressively, validation by consensus, implementation verified by unit tests -and fed back through Reflect. All of -it framework-agnostic, all of it usable on its own. - ---- - -But notice what you're still doing: you invoke `/spec-planning`, then you invoke -`/spec-validate`, then you invoke `/implement-mainspec`. You're driving every -step, one feature at a time, sitting at the keyboard the whole way through. - -The loop is good. What if the *project itself* ran it for you — picked up a -feature request, planned it, validated it, implemented it, and handed you back a -finished pull request while you did something else? - -That's the leap from a skill library to a **harness**. - -→ [Chapter 3 — The agent harness](./3-the-agent-harness.md) diff --git a/docs/3-the-agent-harness.md b/docs/3-the-agent-harness.md deleted file mode 100644 index 633ff44..0000000 --- a/docs/3-the-agent-harness.md +++ /dev/null @@ -1,256 +0,0 @@ -# Chapter 3 — The agent harness - -*The system: deterministic code driving probabilistic code to a guaranteed output.* - -Here is the whole promise of this chapter in one sequence: - -> You describe a feature to your project's `/intent` and confirm it. Then you -> walk away. The project plans the feature, validates the plan, implements it, -> runs its checks, opens a pull request, answers the reviewer's comments — and -> hands you back a PR that's ready to merge. You come back to finished work you -> never typed. - -That's the harness. It takes the Chapter 2 loop — `/spec-planning` → -`/spec-validate` → `/implement-mainspec` — that you used to drive by hand, and -**runs it autonomously**, end to end, while you do something else. - -Name what this is, because the name is the design: **harness engineering** — -building a system with defined inputs and defined outputs out of deterministic -code and probabilistic code, where the deterministic code invokes the -probabilistic code and controls the flow to a guaranteed, well-defined output. -The input is a PRD with a runnable definition of done. The output is **a PR -that is either ready to merge or STUCK with a diagnosis** — the system never -hands back "maybe." Everything in this chapter is in service of that contract, -and of the question it raises: *why would you trust a machine to do this -unattended?* - -## Two tiers: one harness, N environments - -The harness is not something you install into a project. It's its own repo — -**the harness repo** — that operates on any number of project repos, called -**environments**: - -``` -HARNESS REPO (yours, one) ENVIRONMENT REPOS (your projects, many) - bin/context-specs the CLI AGENTS.md the eager contract - scripts/ the dispatchers .claude/skills/intent/ project-owned /intent - skills/ canonical skills .claude/skills/expert/ long-term memory - state// runtime state scripts/bootstrap-worktree.sh, local-checks.sh - .harness/env this env's dials -``` - -The dividing line is a single test: *could you write it without reading the -project's code?* Yes → it lives in the harness repo, where improving it once -improves every environment. No → it's **Software 3.0**, generated by an LLM -reading that project, committed to that project, evolving with it. - -The two tiers meet through symlinks: `context-specs add ` links the -canonical skills into an environment's `.claude/skills/` (gitignored — they're -the harness's, not the project's). Two skills are deliberately *not* linked, -because they are the project's two owned levers: **/intent** (installed as a -committed copy — how well a project expresses intent is one of the biggest -levers it has) and **the Expert** (the long-term memory, Chapter 4). The setup -itself demonstrates the discipline: the CLI does the deterministic half, then -the `/env-init` skill reads the project and generates the Software 3.0 half. - -## The autonomous loop - -A feature flows through the harness as a sequence of states. Each state is -advanced by a skill; the next skill fires when the previous one's output appears -on disk: - -```mermaid -flowchart TD - Intent["/intent (you, once)\nPRD + runnable definition of done"] --> Claim[Harness claims the work] - Claim --> Plan["/spec-planning"] - Plan --> Validate["/spec-validate"] - Validate --> Implement["/implement-mainspec\n(signal loop per slice)"] - Implement --> Checks["local-checks.sh\n(lint, types, fast tests)"] - Checks --> PR[Open pull request] - PR --> Review[Reviewer posts findings] - Review -->|findings| Respond["/address-feedback"] - Respond --> Review - Review -->|no findings left| Ready[Ready for your review] - Ready --> You([You merge]) -``` - -The only human touch in that diagram is the first box and the last. In between, -the project builds the feature itself. The reviewer/responder exchange is bounded -so it can't argue forever, and if any step genuinely can't make progress, the -harness stops and hands you the problem rather than faking success — more on both -below. - -### `/intent` — the goal, pinned down - -The loop begins with the single human-attentive skill in the chain. `/intent` -turns an open-ended idea into two coupled artifacts: - -- `prds//prd.md` — the prose: **why** this exists and **what** "done" - means; -- `prds//run-prd-test.sh` — the executable: **how you'll know** it's - done. It exits 0 when the feature is built. - -The runner is the load-bearing idea, and it's what makes the harness -**goal-based**: the runner *is* the goal, and the loop keeps invoking the model -until the goal is met or the retry caps call it honestly unreachable. Prose -drifts and "done" becomes an argument; an exit code doesn't. Before `/intent` -commits anything, it runs the script against today's unbuilt code and confirms -it fails **for the right reason** — because the behavior is genuinely absent, -not because of a typo or a missing dependency. That's the empirical proof that -the test actually corresponds to the intent. - -Once confirmed, the PRD lands on a branch and the harness takes over. - -## Why you can trust it: artifacts are the state - -The reason it's safe to leave this running is almost boring, and that's the -point. **The harness keeps no hidden state.** There is no daemon holding "I'm -currently on step 3" in memory, no queue, no coordination service. The complete -state of every feature is observable from two things: the files on disk and the -branches in git. - -A small bash script — the **dispatcher** -([`scripts/poll-and-dispatch.sh`](../scripts/poll-and-dispatch.sh)) — wakes up -periodically, takes an environment as its argument, reads that environment's -state fresh, and decides the single next step for each active feature. Its core -is an `if/elif` chain: *planning output absent? run planning. Present but -validation absent? run validate.* The chain **is** the state machine; the -artifacts on disk **are** the state. - -Three consequences fall out of that design, and together they're why the machine -is trustworthy: - -- **Crash recovery is free.** Kill the dispatcher mid-step — `kill -9`, a dead - laptop, a closed lid. The next tick re-reads disk, sees the half-finished - state, and resumes. Nothing to clean up, because nothing was ever held in - memory to lose. -- **Every step runs in a fresh context window.** The dispatcher doesn't *do* the - work; it shells out to a brand-new `claude -p` process per skill. Each skill - reads what it needs from disk, does its job, writes its output, and exits. No - step inherits another's polluted window — the Chapter 1 problem, solved by - construction. (This is also why the loop can run for hours without the context - rot a single long session would accumulate.) -- **The dispatcher itself contains no LLM.** The decision of *what runs next* is - pure, deterministic bash. The intelligence is in the skills; the routing is - mechanical. That's what makes "what will it do next?" answerable just by - looking at disk — no model in the loop to second-guess. - -And one consequence for your working tree, because it's the one developers ask -about first: **the harness never touches your checkout.** It operates on your -clone only through git *refs* — fetching, pushing, claiming branches — and does -all its work in *sibling worktrees* (`-harness-`) it creates and -tears down itself. Your uncommitted work is structurally out of its reach. - -These properties have names and precise statements. When you want the rigorous -version — what holds under concurrency, what each layer guarantees, how recovery -composes — read the **[design invariants](./invariants.md)**. This chapter gives -you the intuition; that document gives you the proof. - -## Verification the agent cannot talk past - -Autonomy is only safe if "done" can't be faked. So the harness leans on checks -that run **regardless of what the agent decides**, fastest to slowest: - -1. **Pre-commit hooks** — linters, formatters, type checks on changed files. -2. **Slice unit tests** — each slice's tests, run during implementation. -3. **`local-checks.sh`** — the cheapest gate before a PR: lint, typecheck, the - fast unit suite, skip-detection, and any custom project lints. It proves - **correctness, not coverage** — it blocks on real defects and merely warns on - style. -4. **The PRD runner** — `./prds//run-prd-test.sh` must exit 0. This is - the definition of done, and because it can mix deterministic shell checks with - an LLM-as-judge, "runnable" doesn't force everything into unit-test shape. - -The agent doesn't get to decide whether these run — they run, and the git/CI -layer enforces them independently. Crucially, **silencing a check counts as -bypassing it**: an agent may never add a suppression directive, weaken a config, -or skip a test to get to green. A check it can't pass honestly is one it lets -fail. - -## When it can't make progress: STUCK - -Sometimes a feature genuinely can't get through a step — a plan is subtly wrong, -a check won't pass honestly. The harness doesn't loop forever, and it won't fake -success. -Every step has a bounded retry budget; when a step hits its cap, the dispatcher -declares the feature **STUCK**, posts a diagnostic to the PR, and halts that -feature until you step in. - -What it hands you is deliberate. Not just "it failed" — a session log of every -`claude -p` invocation across the chain (so you can open any trace and see what -the agent saw), a tail of the failing output, and a **diagnosis-first -checklist**. The checklist's first item isn't "fix the code." It's *identify -which piece of context misled the agent* — a stale Expert note, a thin spec, a -PRD that left something out — and correct that first. Because if the context that -caused the failure stays wrong, the same class of failure comes back the next -time a feature touches that area. - -STUCK is the other half of the output contract. Ready-to-merge and STUCK are -both *finished* states — the system completed its run and told you the truth -about which one you got. And the ratio between them is your metric: every STUCK -names the context to improve, and Chapter 4 is about how those improvements -compound. - -## The branch namespace is the work queue - -There's no separate database of "what work exists." The branches *are* the -registry: - -``` -prd// ← /intent output. The waiting queue. An atomic rename - to feature/ is how the harness claims it. -feature/ ← active implementation lane. -main ← humans merge here. Never pushed to directly. -learn/ ← auto-generated memory update (Chapter 4). -``` - -Claiming a feature is a single atomic git operation — renaming `prd//` -to `feature/`. If two harnesses ever race for the same work, whichever pushes -the rename first wins and the other simply moves on. No lock service, no -coordination daemon; git refs are the lock. By default each developer's harness -watches only their own `prd//*` queue, so your harness is your personal -assistant, not a shared teammate. - -## Running it: the CLI - -The deterministic half of the system extends one layer up — a small CLI in the -harness repo schedules the dispatcher: - -```bash -npx context-specs init my-harness # create your harness repo (once) -context-specs add ~/code/myapp # register an environment, link the skills -# in ~/code/myapp: claude → /env-init (the Software 3.0 half, then merge its PR) -context-specs start # walk away -``` - -`start` runs one background supervisor per environment — a build loop and a -memory loop (Chapter 4). The scheduling protocol is nothing more than the -dispatcher's exit code: **0** means idle (sleep the interval, default 5 -minutes), **10** means "work advanced" (re-invoke immediately). That second case -matters: a claimed PRD marches through planning → validate → implement at -machine speed, while idle polling stays cheap. Errors back off exponentially. A -STUCK feature reports idle — a stuck environment never hot-loops. - -Because each environment gets its own supervisor, own lock, and own state, -**working on multiple projects at once is the default**, not a mode. -`context-specs status` shows every environment's features and phases in one -table; `context-specs run ` does a single foreground pass when you'd rather -watch; `logs -f` follows the loop; `doctor` checks the wiring. - -The trigger is still the portable part: the same dispatcher that a laptop -supervisor invokes can be invoked by cron or a server runner. When a team -outgrows local laptops, they move the *scheduler* and keep everything else. -It's an upgrade path, not a rewrite. - ---- - -So the harness builds features on its own, and refuses to fake the ones it can't. -That alone would be worth having. But there's a second thing it does, and it's -the one that makes the project genuinely *yours* over time. - -Every feature that merges teaches the project something — a new pattern, a -constraint nobody had written down, a rule worth enforcing forever. A harness -that only *built* features would relearn those lessons every time. This one -doesn't. It remembers. - -→ [Chapter 4 — Continuous improvement](./4-continuous-improvement.md) diff --git a/docs/4-continuous-improvement.md b/docs/4-continuous-improvement.md deleted file mode 100644 index 6ff0793..0000000 --- a/docs/4-continuous-improvement.md +++ /dev/null @@ -1,145 +0,0 @@ -# Chapter 4 — Continuous improvement - -*The flywheel — the harness gets better every merge.* - -A harness that only built features would be a fast worker with no memory. Each -feature would start from the same blank slate; the same hard-won lesson — *this -codebase puts query-param pages behind SSR*, *never import `service` from -`repo`* — would have to be rediscovered, or re-explained by you, every single -time. That's the context decay of Chapter 1, but across features instead of -within a session. - -The harness closes that gap. **When code lands on `main`, the project updates its -own long-term memory.** The next feature starts knowing what the last one taught. - -```mermaid -flowchart LR - Merge([Merge to main]) --> Learn["/learn\nreads the merged diff"] - Learn --> Reconcile{Reconcile against\ncurrent memory:\nanything to add,\nedit, or delete?} - Reconcile -->|no — common| Noop[Nothing to learn.\nMost merges teach\nnothing durable.] - Reconcile -->|yes| Route[Route each change to\nexactly one destination] - Route --> PR["learn/ PR\nyou review and merge"] -``` - -The skill that does this is [`/learn`](../skills/harness/learn/SKILL.md), -and a few principles make it trustworthy rather than a source of drift. - -## Ground truth only — one write path - -The most important rule: **memory reflects what is committed to `main`, never -what is planned.** PRDs and specs describe intent; code is reality. So `/learn` -only ever writes from a *merged diff* — never from a branch in flight, never from -a feature that might still be abandoned. - -That gives the whole system a single, auditable **write path** for memory: a -human merges a feature; `/learn` observes the result; the change to memory lands -on its own `learn/` pull request that a human reviews and merges. Memory is -never auto-written by a skill mid-task, never updated speculatively. There is -exactly one door, and it opens only on ground truth. - -This is also how a STUCK resolution (Chapter 3) compounds: when you correct the -misleading context on a feature branch and merge it, that correction is *in the -diff* `/learn` reads. The fix you made by hand becomes permanent project memory, -automatically. - -## Two memory shapes, opposite costs - -The harness keeps memory in two places, and the difference between them is the -whole discipline — it isn't an implementation detail: - -- **The Expert** *(from Chapter 2)* is **lazy memory** — pulled on demand. It - enters a context window only when a skill deliberately consults it. You pay - tokens for it *only when it earns them*. This is the default home for real - knowledge: architecture, patterns, how things get verified here. -- **`AGENTS.md`** is **eager memory** — loaded automatically into every agent - that touches the folder, before anyone knows whether it's relevant. You pay - for every line on *every* session. So the bar for putting something here is - much higher. - -Because eager memory is a standing tax and lazy memory is paid only when -consulted, the two compose as **map and territory**: `AGENTS.md` is a short table -of contents that *points into* the Expert; it never duplicates the dense -knowledge. A monolithic `AGENTS.md` rots, crowds out the task, and turns -"everything important" into "nothing important." Keep it a map; keep the density -in the Expert. (Using `AGENTS.md` — the vendor-neutral, open file every harness -reads — rather than a tool-specific one is also what keeps your project's memory -*yours*, portable across whatever agent you point at it.) - -## The four destinations — where a learned fact goes - -`/learn` is disciplined about *where* a remembered fact lands. Every fact worth -keeping routes to **exactly one** place: - -| Destination | Use when | What it costs | -|---|---|---| -| **A lint** (`scripts/lints/*`) | The rule is mechanically checkable — pass/fail needs no judgment | Enforced on every PR forever; the error message doubles as a fix prompt | -| **Eager prose** (`AGENTS.md`) | It must be known *before* an agent would think to consult the Expert, and clears a strict five-part bar | Paid every session — the high bar | -| **Lazy prose** (an Expert reference file) | It's useful when *deliberately reasoning* about an area | Paid only when consulted — the usual home | -| **Nowhere** | It's inferable from the code, taste-only, or transient | — | - -Most facts go to the last two. A **nothing-to-learn** outcome — "this merge -teaches nothing durable" — is a **common and correct** result, not a failure: -vuln fixes, refactors that don't change shape, and routine bug fixes usually -change no memory at all, so `/learn` prints `nothing to learn` and opens no PR. -The system improves by accumulating signal, not noise, and *preferring nothing -over noise* is what keeps the Expert worth reading. - -## Lints — the memory an agent cannot ship past - -The top row of that table deserves its own spotlight, because it's the -highest-value thing the harness can learn. A **lint** is just a short script: -glob some files, check a fact, exit non-zero with a remediation message. It beats -prose for two reasons: - -1. **The error message is a prompt.** It doesn't say "violation" — it says *how - to fix it*, feeding remediation straight into the agent's window so it - self-corrects. A prose rule is advice the agent *might* follow; a lint is a - rule it *cannot ship past*, plus the fix. -2. **It scales the way agents scale.** Once written, it applies to every file and - every future PR at once. - -So the most durable thing your project owns is the set of custom lints it grows -over time — layer-dependency direction, no raw SQL interpolation, -structured-logging-only, naming rules, file-size caps. Promotion is -conservative: a discovered invariant lives as prose first and is promoted to a -lint only on recurrence, and a drafted lint **must pass against the just-merged -code** before it's wired in (the inverse of `/intent`'s right-reason check — a -lint that reddens the merge it was born from is wrong). - -## Reconcile, don't accumulate - -Memory is a *current model of `main`*, not an append-only log — so `/learn` doesn't -just add. On every merge it runs a three-pass reconcile against the merged diff, -inline in the main agent (no subagent voting): it **deletes** reference files whose -anchor code is gone, resolves **contradictions** between files that now disagree, -and **edits** claims the diff has invalidated. Adds, edits, and deletes all ride -on the same `learn/` PR, each with a one-line justification citing the diff -hunk that motivated it — if it can't be justified from the diff, it's dropped. -That inline justification is the bar that keeps memory honest, and everything that -survives lands on a reviewable, revertible PR. You stay the final gate. - -Inside the Expert, the files are kept small and topic-focused, cross-linked with -`[[wikilinks]]` so an agent reads the one-line index, opens only what's relevant, -and follows links to the rest — progressive disclosure, so consulting memory -never means loading all of it. - -## What you have at the end of this chapter - -A project that not only builds features unattended, but gets measurably easier to -build the next feature in — because every merge that taught something durable put -that lesson where the next agent will find it, at the right cost, behind a human -merge. The harness compounds. - ---- - -Step back and notice what's happened to your job. The machine plans. It -implements. It verifies. It remembers. The typing — the part that used to be most -of the work — is gone. - -That doesn't make you redundant. It makes the *remaining* part the whole job, and -the remaining part is the one a machine structurally cannot do: deciding what's -worth building, judging whether what got built is right, and improving the -context so the harness keeps getting better. That's not a side activity anymore. -It's the loop you live in. - -→ [Chapter 5 — The human loop](./5-the-human-loop.md) diff --git a/docs/5-the-human-loop.md b/docs/5-the-human-loop.md deleted file mode 100644 index bbd21d0..0000000 --- a/docs/5-the-human-loop.md +++ /dev/null @@ -1,185 +0,0 @@ -# Chapter 5 — The human loop - -*Freed from typing, you improve the harness.* - -Chapters 3 and 4 built a machine that builds and remembers. This chapter is about -what you do now that it does. The honest answer is: **the most important part** — -the part the machine structurally cannot do. - -The governing line comes from Andrej Karpathy: *"you can outsource your thinking -but you can't outsource your understanding."* It draws a sharp boundary: - -- **Verifiable work → outsource it freely.** Syntax, API recall, implementation - mechanics. The model is superhuman here. Spending your attention on it is - waste. -- **Unverifiable work → you must own it.** Whether this is the right thing to - build, whether the abstraction is sound, whether the edge cases are handled for - good reasons, whether the UX feels right. Errors here are subtle and don't - announce themselves — exactly where your understanding has to be load-bearing. - -The harness took the first category. The human loop is you, deliberately working -the second. It has three phases, and they form a closed cycle: - -``` - Understanding ──▶ Intent ──▶ [ the harness builds ] ──▶ Evaluate - build your model express Chapters 3 & 4 walk the result, - of the problem what to run it, judge it, - space build improve the context - ▲ │ - └──────────── evaluating deepens understanding ──────────┘ -``` - -## The two loops interlock - -The human loop and the machine loop aren't parallel tracks — they feed each -other, and that coupling is the design: - -> **Your loop's output is the harness's input. The harness's output is your -> loop's input.** - -You produce intent (a PRD); the harness consumes it and produces a pull request; -you consume that PR by evaluating it; what you learn sharpens the next intent. -Neither loop is complete without the other. The machine exists to serve your -loop — and naming your loop explicitly is what keeps *your* job legible as the -machine takes over more of the typing. - -Each phase is a built skill. - -## Understanding — `/wiki-init` - -Before you can express good intent, you need a real model of the problem space: -the domain, the prior art, the constraints, the trade-offs. The Understanding -phase builds *your* model, not the agent's. - -[`/wiki-init`](../skills/human-loop/wiki-init/SKILL.md) stands up a -standalone, LLM-maintained knowledge base in the shape of **Karpathy's "LLM -Wiki"**: rather than retrieving and re-synthesizing on every question, you -synthesize **once, at ingest time**, into durable, cross-linked pages that -compound as sources accumulate. You curate sources and ask questions; the LLM -does the bookkeeping humans abandon wikis over — updating cross-references, -reconciling pages, keeping the map current. - -This wiki is deliberately **not** a project artifact, and that's the bright line -worth holding: - -- The **wiki** is cross-project **domain and architecture** knowledge, written to - be read **by you**. It lives in its own repo, outside any codebase. -- The **Expert** (Chapters 2 & 4) is per-project **code** memory, written to be - read **by agents**. - -The payoff is direct: a richer model of the domain means a sharper `/intent`. You -arrive at the next phase already understanding the concepts, the constraints, and -the trade-offs — so the feature you ask for is the right one. - -## Intent — `/intent` - -This is the front bookend, and you met it in Chapter 3 as the harness's entry -point. From the human loop's side, [`/intent`](../skills/human-loop/intent/SKILL.md) -is where understanding becomes a buildable thing. Its discipline is worth -restating because it's where your thinking does its work: - -- **Elicit outcomes, not solutions.** People arrive describing a solution ("add a - `/api/search` endpoint"); the job is to surface the *need* underneath ("readers - can't find a post by title") and the observable outcome that would satisfy it. -- **"How would we know that's true?"** is the throughline. Asked of every desired - outcome, it converts a wish into both a sharp prose criterion *and* a concrete - check — the two coupled artifacts (`prd.md` + `run-prd-test.sh`) born together. -- **You don't write the runner; the Expert drafts it, you review.** This keeps - verification grounded in how the project actually works, not your instinct in - the moment. - -`/intent` is a *coordinator, not a knowledge holder* — the domain reasoning comes -from the Expert. Your contribution is the understanding from the previous phase -and the judgment about what's worth building. Confirm the PRD, and the machine -takes it from there. - -## Evaluate — `/evaluate-pr` and `/evaluate-sessions` - -The back bookend, and the mirror of `/intent`. The harness hands you a finished -PR; evaluation is where you do the unverifiable work the machine couldn't. There -are two skills, because there are two things to evaluate. - -### `/evaluate-pr` — evaluate *what was built* - -[`/evaluate-pr`](../skills/human-loop/evaluate-pr/SKILL.md) produces two -outcomes. The tangible one: merge, fix-and-push, or close. The intangible one — -**the one that matters more** — is *you* understanding the change deeply enough -to defend every scenario and design decision in it. - -That intangible output is the literal mechanism that closes the loop back to -Understanding and sharpens the next Intent. So the skill is a teacher and a taste -partner, not a second linter: the bot reviewer already caught the mechanical -defects, so it *ingests* those findings and sets them aside, then spends your -attention on what a bot structurally can't judge — is this simpler than it could -be, is the abstraction sound, does the UX feel right? It runs the system with -you, walks the definition-of-done scenarios live, and probes Socratically rather -than lecturing. The understanding gate is soft but real: it ends on "do you feel -you understand this change?" and skipping the walk-through is an explicit -opt-out, never a silent rubber-stamp. - -If the walk surfaces something to change, **you fix it here and push** — you -never hand work back to the loop. You are the last mile. - -### `/evaluate-sessions` — evaluate *how it was built* - -[`/evaluate-sessions`](../skills/human-loop/evaluate-sessions/SKILL.md) is -where the human loop reaches back and improves the harness itself. The harness -posts the full `claude -p` build trail on every PR — the sessions the agents ran. -This skill reads that trail *with you* to find where the project's context served -the agents and where it failed them: where an agent re-derived something the -Expert should have told it, followed a stale `AGENTS.md` pointer, or guessed -because a spec was thin. - -What you find turns into two durable outcomes — the **flywheel**: - -> *Observe a trace → capture it as an eval → fix the context → it persists as a -> regression test.* - -- **Evals** — when a session shows a skill behaved well or badly *given the - context it had*, freeze that as a runnable check under `evals/`. An eval is a - regression test over the harness's **own skills and context** (the analog of - testing a prompt), distinct from the PRD runner, which tests the product. -- **Context fixes** — when a piece of context misled an agent, fix the Expert - reference file, the `AGENTS.md` pointer, or the skill. - -This is the moment the framing of the whole book becomes literal: every PR the -harness builds is a graded trial of your project's context, and every eval you -capture makes the project a little better at building itself next time. You're -not auditing one PR — you're **tuning the harness.** - -## Memory still has one write path - -Notice what evaluation does *not* do: it doesn't write memory directly. Whatever -you learn here isn't ground truth yet, because the change isn't merged yet. So -the insight either becomes a pushed fix that rides into `main` — where `/learn` -(Chapter 4) picks it up as ground truth to extend, not second-guess — or it lives -in your head and sharpens the next Intent. Evals and context fixes land on a -branch and reach memory the same way: through a merge. The single write path of -Chapter 4 holds. You may now *seed* memory deliberately; you still never bypass -the door. - -## The three places you steer - -Across the whole system, you touch the machine at exactly three points — and -every one of them is a phase of this loop: - -| You... | Human-loop phase | What it does to the machine | -|---|---|---| -| Confirm a PRD | end of **Intent** | starts the build | -| Evaluate and merge a PR | **Evaluate** | ends the build; triggers `/learn` | -| Unstick a STUCK feature | a forced detour into **Evaluate** | corrects the context, then merges | - -Three touchpoints. Everything between them is the machine. Everything *at* them -is judgment — yours. - ---- - -So here's where we've arrived. The project plans, implements, verifies, and -remembers on its own. You spend your time understanding the problem, expressing -intent, and evaluating outcomes — and when you evaluate, you don't just approve -work, you improve the thing that produced it. - -That's not a new workflow bolted onto coding. It's a different relationship to -your own project. Worth saying plainly, because it's the whole point. - -→ [Chapter 6 — The mindset shift](./6-the-mindset-shift.md) diff --git a/docs/6-the-mindset-shift.md b/docs/6-the-mindset-shift.md deleted file mode 100644 index 30fb652..0000000 --- a/docs/6-the-mindset-shift.md +++ /dev/null @@ -1,85 +0,0 @@ -# Chapter 6 — The mindset shift - -*The payoff.* - -Read the first five chapters and a single line falls out of them: - -> **Your project is not a codebase you type into. It's a harness you tune.** - -Read it literally: it describes what the previous chapters actually built. The -harness plans features, implements them, -verifies them, and remembers what it learns. The code is an *output* of the -system now — something the harness produces — not the thing you spend your hours -authoring. - -The shift this asks of you is the hard part, because it's a shift in where you -put your attention. - -## From syntax to context - -The old craft was syntax: knowing the API, writing the loop, getting the types to -line up, remembering how this codebase does things. That craft is exactly the -**verifiable** work from Chapter 5 — the work the model is superhuman at. Keep -spending your attention there and you're racing a machine at the one game it -always wins. - -The new craft is **context engineering** — the lever from Chapter 1, now wielded -deliberately and at every level: - -- You shape the context the harness reasons over (the Expert, `AGENTS.md`, the - specs). -- You decide what becomes a lint the agent can't ship past, and what stays - flexible prose. -- You read the build trail to find where the context failed an agent, and you fix - it so the next feature benefits. - -When a feature comes out wrong, the question is no longer "let me go fix that -code." It's "what did the agent not know, and where should that knowledge live so -it never bites us again?" Fixing the code fixes one feature. Fixing the context -fixes the *class*. - -## The three things that stay yours - -Strip away the typing and what's left is the work that was always the most -valuable, now unobscured. Three things, and they are not going anywhere: - -1. **Deep understanding of the problem space.** The harness can build anything you - can specify; it cannot tell you what's worth specifying. That comes from your - model of the domain — which is why the Understanding phase exists, and why it - compounds (Chapter 5). -2. **Theorizing and expressing intent.** Deciding what to build, and pinning - "done" to something executable. This is judgment under uncertainty — the part - no exit code can hand you. -3. **Evaluating outcomes and improving the context.** Judging whether what got - built is *right* in the ways a machine can't verify — and turning that judgment - into better context, so every future feature inherits it. - -Understand the problem. Express the intent. Evaluate the result and improve the -harness. That's the loop. The machine does the rest. - -## Why it compounds - -The reason this is worth the shift, and not just a rearrangement of chores: **the -system gets better the more you use it, and it gets better in a direction you -choose.** - -Every merge can teach the Expert something. Every STUCK you resolve corrects a -piece of context for good. Every eval you capture freezes a behavior so a future -change can't silently regress it. A codebase you type into is a constant cost — -it decays, it needs maintenance, every feature starts roughly where the last one -did. A harness you tune is an *appreciating asset* — each feature leaves the -project a little more capable of building the next one. - -That's the whole bet of Context Specs, stated plainly: - -> Stop spending yourself on the work a model does better than you. Spend yourself -> on understanding, intent, and context — and let the project you've turned into -> a harness compound everything you put in. - ---- - -That's the story. To go deeper on any layer, the chapters point into the actual -skills under [`skills/`](../skills/); to understand *why* the -harness is safe to leave running, read the **[design invariants](./invariants.md)**. - -← [Back to the start](./README.md) diff --git a/docs/README.md b/docs/README.md index 72350b5..0e0f388 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,90 +1,69 @@ -# Context Specs — the full story +# Context Specs documentation -This is the long-form documentation for Context Specs. The top-level -[README](../README.md) is the elevator pitch; this is the book. +Context Specs is [harness engineering](./concepts/harness-engineering.md) applied to +building software: you express intent, and a deterministic harness drives a coding +model all the way to a pull request that is either **ready to merge** or **STUCK +with a diagnosis**. Over time you improve the *system* — its context, its memory, +its checks — so more features come back ready and fewer come back stuck. -It's written to be read **in order**. Each chapter ends where the next one -begins — by the last page you should see why a coding project, run well with -agents, stops looking like a codebase you type into and starts looking like a -**harness you tune**. +New here? The top-level [README](../README.md) is the elevator pitch. For the full +narrative, read the [overview](./overview.md). Otherwise, jump straight to a concept +or a task below. -## The through-line +## Overview -This project is **harness engineering in practice**. Harness engineering is -building a system — defined inputs, defined outputs — out of deterministic code -and probabilistic code, where the deterministic code invokes the probabilistic -code and controls the flow all the way to a guaranteed, well-defined output. +- **[How Context Specs works](./overview.md)** — the narrative tour that connects + every concept in one reading. -Here the input is a PRD with a runnable definition of done, and the output is -**a pull request that is either ready to merge or STUCK with a diagnosis** — -never "maybe." That output is also the system's feedback signal: every STUCK -and every review finding points at a piece of context to improve, and context -engineering — the right context at the right time — is the lever that moves the -ready-to-merge ratio up. +## Core concepts -``` -Context engineering the lever: what enters an agent's window decides everything - │ - ▼ -Spec-Driven Development the harness's short-term memory — plan one feature - │ outside the window, feed it back a slice at a time - ▼ -The agent harness the system: deterministic code driving probabilistic - │ code from PRD to a guaranteed output (PR or STUCK) - ▼ -Long-term memory the flywheel: the project learns every merge, and - │ long-term memory informs every future plan - ▼ -The human loop the goals and the judgment: intent in, evaluation out - │ - ▼ -A mindset shift your project has become a harness; your job is context -``` +Standalone explanations of each idea. Read in any order; they cross-link. -Two memory systems run through everything. The **Expert** (plus `AGENTS.md`) is -the project's *long-term* memory; the specs and slices are *short-term* memory — -the plan for one feature, informed by the long-term memory every time it's -written. Improve the long-term memory and every future feature plans better. -It's written back on two rhythms: **Reflection** in the hot path (after each -slice) and **/learn** off the hot path (after each merge — the system -consolidating what it learned while nothing is running, the way agents like -OpenClaw "dream"). +- **[Harness engineering](./concepts/harness-engineering.md)** — what a harness is + (Agent = Model + Harness), and the discipline the whole system rests on. +- **[Context engineering](./concepts/context-engineering.md)** — the core lever: + the right context in the window at the right time. +- **[The two-tier architecture](./concepts/two-tier-architecture.md)** — one harness + repo driving N environments; the Software 3.0 dividing line. +- **[The dispatcher](./concepts/the-dispatcher.md)** — the deterministic engine; + artifacts as state; a fresh window per step. +- **[Spec-Driven Development](./concepts/spec-driven-development.md)** — short-term + memory: context engineering for one feature. +- **[Long-term memory](./concepts/long-term-memory.md)** — the Expert, `AGENTS.md`, + and lints; how the harness remembers. +- **[The output contract](./concepts/output-contract.md)** — the runnable definition + of done; ready-to-merge vs. STUCK. +- **[Continuous improvement](./concepts/continuous-improvement.md)** — operating at + the system level; the ready-to-merge ratio; the flywheel. +- **[The human loop](./concepts/the-human-loop.md)** — understand → intent → + evaluate; the part only you can do. -And the whole thing is **goal-based**: `/intent` pins the goal down as a -runnable test, and the harness keeps invoking the model until the goal is met — -or the retry caps turn honest failure into STUCK. +## How-to guides -## The chapters +Task-oriented steps for getting things done. -1. **[Context engineering](./1-context-engineering.md)** — what it actually is, - and why the context window is the scarce resource everything else is fighting - over. -2. **[Spec-Driven Development](./2-spec-driven-development.md)** — the harness's - short-term memory: experts, specs, temporal slicing, reflection, consensus - validation. Usable on its own, no harness needed. -3. **[The agent harness](./3-the-agent-harness.md)** — the system itself: one - harness repo driving N environments, a deterministic dispatcher, and why you - can trust a machine to run it unattended. -4. **[Continuous improvement](./4-continuous-improvement.md)** — the flywheel: - long-term memory, the destinations for a learned fact, and lints the agent - cannot ship past. -5. **[The human loop](./5-the-human-loop.md)** — once the machine does the - typing, what's left is the part only you can do: Understanding → Intent → - Evaluate. -6. **[The mindset shift](./6-the-mindset-shift.md)** — the payoff. Your project - is a harness now. Here's how the way you work changes. +- **[Create a harness](./how-to/create-a-harness.md)** — `init` your one harness + repo. +- **[Add an environment](./how-to/add-an-environment.md)** — register a project. +- **[Initialize a project](./how-to/initialize-a-project.md)** — generate the + Software 3.0 half with `/env-init`. +- **[Express intent](./how-to/express-intent.md)** — turn an idea into a PRD + + runnable definition of done. +- **[Run the harness](./how-to/run-the-harness.md)** — start, observe, and stop the + loops. +- **[Unstick a feature](./how-to/unstick-a-feature.md)** — resolve a STUCK by fixing + the context first. +- **[Evaluate a PR](./how-to/evaluate-a-pr.md)** — evaluate *what* was built. +- **[Improve from build traces](./how-to/improve-from-traces.md)** — evaluate *how* + it was built; capture evals and context fixes. -### Reference +## Reference -- **[Design invariants](./invariants.md)** — the properties the harness holds no - matter what crashes, races, or restarts. Read this when you want to understand - *why* the machine is safe to leave running. (Optional; you can also hand it to - an agent to give it a deeper model of the harness.) - -## Where the code lives - -The deterministic half is the [`context-specs` CLI](../bin/) and the dispatcher -scripts under [`scripts/`](../scripts/); the probabilistic half ships as Agent -Skills under [`skills/`](../skills/). The chapters point at the specific skill, -script, or reference file that implements each idea, so you can read the story -and then go read the source. +- **[The `context-specs` CLI](./reference/cli.md)** — every command, flag, and exit + code. +- **[The pieces](./reference/skills.md)** — the full catalog of CLI commands, + dispatchers, and skills. +- **[State and branches](./reference/state-and-branches.md)** — the branch namespace + and on-disk layout. +- **[Design invariants](./reference/invariants.md)** — the properties that make the + harness safe to leave running. diff --git a/docs/concepts/context-engineering.md b/docs/concepts/context-engineering.md new file mode 100644 index 0000000..f190fae --- /dev/null +++ b/docs/concepts/context-engineering.md @@ -0,0 +1,67 @@ +# Context engineering + +Context engineering is the practice of controlling what goes **into** — and what +stays **out of** — a coding agent's context window. It is the single biggest +lever you have when you build software with agents, and most other concepts in +Context Specs are an application of it at a larger scope. + +## Why the window is the scarce resource + +A coding agent does not "know" your codebase. At any instant it knows exactly +what is in its context window: the conversation so far, the files it has opened, +the tool output it has seen. That window is finite, and it degrades in three ways +that are easy to forget: + +- **Context decay** — in a long session, older messages lose influence. The agent + attends most to what is recent and quietly discounts what came before, so a plan + laid out twenty tool calls ago is no longer really steering the work. +- **Context pollution** — left to roam, an agent retrieves context on its own: it + greps, opens files, follows imports. Much of what it pulls in is irrelevant, and + every irrelevant token crowds out a relevant one. +- **Compaction loss** — when the window fills, the session is summarized to make + room, and you do not get to choose what is dropped. Critical details disappear + and the agent "forgets" — not from carelessness, but because the bytes are gone. + +None of these are quirks of a particular model. They are consequences of working +inside a finite window, and they intensify as a task grows — exactly when holding +a coherent picture matters most. + +## The discipline: choose, don't dump + +The intuitive move is to load everything up front — the whole architecture, every +convention, all the relevant files — and then start. That front-loads pollution +and makes compaction near-certain before the agent has done anything. + +Context engineering is the opposite discipline: **the agent dynamically pulls the +context it needs, when it needs it, and the substrate it pulls from is the +filesystem.** Two techniques do most of the work: + +- **Externalize the durable stuff.** Anything that must survive a long session — + the plan, the conventions, the domain knowledge — lives in files on disk, not in + the conversation. Files do not decay and are not compacted; the agent re-reads + them precisely when they are relevant. +- **Progressive disclosure.** You hand the agent a *pointer* — a short, high-level + description with a path — not dense detail. The agent reads the description + first, decides whether it needs more, and only then opens the dense source. The + window stays small and focused, holding just what the current step requires. + +The filesystem is what makes this possible. A file is a unit of context the agent +can choose to load or ignore; a directory of well-named files is a menu it can +navigate just-in-time. Much of the skill of context engineering is the skill of +*organizing that menu* — so the right thing is one obvious read away and the wrong +thing is never accidentally in the window at all. + +## Where it shows up in Context Specs + +The same lever is pulled at every scale of the system: + +| Scope | Application | +|---|---| +| One feature | A [spec](./spec-driven-development.md) externalizes the plan so it cannot decay or compact, and slices it so the agent only loads the piece it is working on. | +| Project knowledge | An [Expert](./long-term-memory.md) is curated knowledge pulled on demand instead of re-explained every session. | +| The whole run | The [dispatcher](./the-dispatcher.md) runs a fresh window per step, so no step inherits another's pollution. | +| Across features | [Long-term memory](./long-term-memory.md) keeps hard-won context alive so future features start from it. | +| You | The [human loop](./the-human-loop.md) is deliberate context engineering — deciding what the agents should have known and putting it where they will find it. | + +Every layer answers the same question at its own scope: *what is the right context +here, and how does it reach the window at the right moment?* diff --git a/docs/concepts/continuous-improvement.md b/docs/concepts/continuous-improvement.md new file mode 100644 index 0000000..3b7b0e5 --- /dev/null +++ b/docs/concepts/continuous-improvement.md @@ -0,0 +1,84 @@ +# Continuous improvement: operating at the system level + +This is the idea at the center of Context Specs: **you work on the system that +produces features, not on the features themselves.** A harness that only built +features would be a fast worker with no memory. This one gets measurably better at +building *your* project every time it builds — and it improves in a direction you +choose. + +## Two ways to fix a problem, very different leverage + +When a feature comes out wrong, you can fix it at two levels, and the difference is +the whole point: + +- **Fix the code.** You correct this one feature and ship it. Nothing else changes. + The next feature starts from the same place the last one did. This is real work, + and sometimes it is all a situation needs — but its leverage is exactly one + feature. +- **Fix the context gap.** You find *why* the agent got it wrong — a thin + definition of done, a missing piece of [long-term memory](./long-term-memory.md), + an environment the agent could not navigate, a rule nobody wrote down — and you + correct *that*. Now every future feature that touches the same area benefits. You + fixed a *class* of failure, not an instance. + +You do both. But **context-gap fixes are the main thing**, because they compound +and code fixes do not. Fixing the code fixes one feature; fixing the context fixes +the class. + +## The metric: the ready-to-merge ratio + +The harness's [output contract](./output-contract.md) gives you a clean signal to +optimize. Every feature ends **ready-to-merge** or **STUCK**, and the ratio between +them is your metric. It is not a vanity number — it is directly actionable, because +every STUCK *names the context to improve*. The job of continuous improvement is to +drive that ratio up: fewer stuck features, more that come back ready, as the +project's context gets sharper. + +A codebase you type into is a constant cost — it decays, it needs maintenance, +every feature starts roughly where the last one did. A harness you tune is an +**appreciating asset** — each feature leaves the project a little more capable of +building the next one. + +## The flywheel has several engines + +Improvement enters the system through more than one path, and they reinforce each +other: + +- **`/learn` (the machine loop).** After every merge, the harness reads the merged + diff and updates [long-term memory](./long-term-memory.md) — routing durable + lessons into the Expert, `AGENTS.md`, or a lint. Automatic, behind a human merge. +- **Lints (the memory an agent cannot ship past).** The highest-leverage + improvement: a recurring lesson promoted to a short script whose error message is + itself a fix prompt. Once written, it protects every future PR. See + [long-term memory](./long-term-memory.md#lints-the-memory-an-agent-cannot-ship-past). +- **Evals (the human loop).** Reading the build trail with + [`/evaluate-sessions`](../how-to/improve-from-traces.md) surfaces where the + project's context served or failed the agents. What you find is frozen as a + runnable eval — a regression test over the harness's *own skills and context* — + and captured as a context fix. +- **Unsticking (the forced detour).** Every STUCK you resolve by correcting the + misleading context, then merging, feeds that correction into `/learn` as ground + truth. See [Unstick a feature](../how-to/unstick-a-feature.md). + +The common shape across all four: + +> *Observe a trace → capture it as an eval or a lint → fix the context → it +> persists.* + +## Why this is the job now + +Strip away the typing — the part a model does better than you — and what is left is +not "less work." It is *higher-leverage* work: shaping the context the harness +reasons over, deciding what becomes a lint versus flexible prose, and reading the +build trail to fix what failed an agent. Fixing the code fixes one feature. Fixing +the context fixes the class. That shift, from operating on features to operating on +the system, is what lets one engineer do far more — and it is the whole bet of +Context Specs. + +## Related + +- [Long-term memory](./long-term-memory.md) — the durable store the flywheel writes + to. +- [The human loop](./the-human-loop.md) — the phases where *you* drive improvement. +- [The output contract](./output-contract.md) — where the ready-to-merge/STUCK + signal comes from. diff --git a/docs/concepts/harness-engineering.md b/docs/concepts/harness-engineering.md new file mode 100644 index 0000000..e21c932 --- /dev/null +++ b/docs/concepts/harness-engineering.md @@ -0,0 +1,76 @@ +# Harness engineering + +Harness engineering is the discipline Context Specs is built on. Understanding it +is the fastest way to understand everything else, because every other concept is +an instance of it. + +## What a harness is + +Start with the equation: + +> **Agent = Model + Harness** + +The **model** is the probabilistic part: given a context window, it produces a +plausible next step. On its own it is a suggestion engine — capable, but with no +guarantees. It can drift, hallucinate, declare success it did not achieve, or +quietly lose the thread in a long session. + +The **harness** is everything else wrapped around the model: the tools +it can call, the skills and prompts that shape each step, the control flow that +decides what runs next, and the checks that decide whether a step actually +succeeded. The harness makes the model's intelligence useful. + +An agent is the two together. When people say "the agent did X," the interesting +engineering is almost always in the harness — the model is a component inside it. + +## The discipline + +> **Harness engineering is building a system — defined inputs, defined outputs — +> out of deterministic code and probabilistic code, where the deterministic code +> invokes the probabilistic code and controls the flow all the way to a +> guaranteed, well-defined output.** + +Read that carefully, because each clause is load-bearing: + +- **Defined inputs, defined outputs.** A harness is a function with a contract, + not an open-ended chat. You know the shape of what goes in and the shape of what + comes out. +- **Deterministic code and probabilistic code.** Both are first-class. The model + supplies intelligence; the deterministic code supplies control, verification, + and repeatability. +- **The deterministic code invokes the probabilistic code.** The control flow is + in the reliable half. The model is called *by* the system; it does not steer + the system. There is no LLM in the decision path deciding what happens next. +- **All the way to a guaranteed, well-defined output.** The system does not stop + at "the model responded." It drives the process until it reaches one of a small + set of defined terminal states — and it always reaches one. + +## The guaranteed output: ready-to-merge or STUCK + +In Context Specs, the input is a PRD with a runnable definition of done, and the +guaranteed output is **a pull request in one of exactly two finished states**: + +- **Ready to merge** — the feature is built and every check passed. +- **STUCK** — the system could not finish honestly, and it hands you a diagnosis + of what blocked it instead of faking success. + +Both are *finished* states. The system never returns "maybe," never returns a +half-built branch with no verdict, and never claims done when it is not. That +guarantee is the whole point of engineering a harness rather than prompting a +model and hoping. The mechanics of how "done" is proven, and what a STUCK hands +you, are covered in [the output contract](./output-contract.md). + +## How the rest of the system follows from this + +Everything in Context Specs is harness engineering applied at a particular scope: + +- The reliability of each step comes from [context engineering](./context-engineering.md) — + the lever that decides what the model reasons over. +- The system's shape is [one harness driving N environments](./two-tier-architecture.md). +- The deterministic control flow is [the dispatcher](./the-dispatcher.md): pure + code, no model in the decision path. +- The guaranteed output is defined by [the output contract](./output-contract.md). +- The harness gets better over time through [continuous improvement](./continuous-improvement.md) — + you operate on the *system*, not the individual feature. +- And [the human loop](./the-human-loop.md) is the part of the job a harness + cannot take: deciding what to build and judging whether what came back is right. diff --git a/docs/concepts/long-term-memory.md b/docs/concepts/long-term-memory.md new file mode 100644 index 0000000..348ffc2 --- /dev/null +++ b/docs/concepts/long-term-memory.md @@ -0,0 +1,131 @@ +# Long-term memory + +Long-term memory is what makes the harness get *better* at building your project, +not just fast at it. Where a [spec](./spec-driven-development.md) is short-term +memory for one feature, long-term memory is durable, cross-feature knowledge: +architecture, patterns, constraints, and the rules the project has learned to +enforce. Improve one shard of it and every future feature plans better. + +## Two memory shapes, opposite costs + +The harness keeps long-term memory in two places, and the difference between them +is the whole discipline — not an implementation detail: + +- **The Expert** is **lazy memory** — pulled on demand. It enters a context window + only when a skill deliberately consults it, so you pay tokens for it *only when + it earns them*. This is the default home for real knowledge: architecture, + patterns, how things get verified here. +- **`AGENTS.md`** is **eager memory** — loaded automatically into every agent that + touches the folder, before anyone knows whether it is relevant. You pay for every + line on *every* session, so the bar for putting something here is much higher. + +Because eager memory is a standing tax and lazy memory is paid only when consulted, +the two compose as **map and territory**: `AGENTS.md` is a short table of contents +that *points into* the Expert; it never duplicates the dense knowledge. A +monolithic `AGENTS.md` rots, crowds out the task, and turns "everything important" +into "nothing important." Keep it a map; keep the density in the Expert. Using +`AGENTS.md` — the vendor-neutral file every harness reads — rather than a +tool-specific one also keeps your project's memory *yours*, portable across +whatever agent you point at it. + +## The Expert: knowledge defined once, pulled on demand + +An **Expert** is a progressively-disclosed knowledge module: + +``` +expert/ # (or expert-{name}/ for an outside domain) +├── SKILL.md # high-level index + routing table, read first +└── references/ # dense knowledge, one topic per file, read on demand + └── {prefix}-{topic}.md +``` + +It is the [context-engineering](./context-engineering.md) menu made concrete: a +short `SKILL.md` the agent sees first, pointing into dense `references/` it loads +only when relevant. Define the knowledge once and it flows automatically through +every phase — you never paste it into a prompt again. Experts are **composable**: +a React Expert and a DynamoDB Expert both contribute to a full-stack feature, and +organizations can layer in private Experts for internal libraries without touching +any existing skill. + +The Expert is one of the two [developer-owned levers](./two-tier-architecture.md). +It is seeded as a skeleton by `/env-init` and grows from there. + +## One write path: ground truth only + +The most important rule keeps memory honest: + +> **Memory reflects what is committed to `main`, never what is planned.** + +PRDs and specs describe intent; code is reality. So the memory loop only ever +writes from a *merged diff* — never from a branch in flight, never from a feature +that might still be abandoned. That gives the whole system a single, auditable +**write path**: a human merges a feature; +[`/learn`](../../skills/harness/learn/SKILL.md) observes the result; the change to +memory lands on its own `learn/` pull request that a human reviews and merges. +There is exactly one door, and it opens only on ground truth. + +```mermaid +flowchart LR + Merge([Merge to main]) --> Learn["/learn\nreads the merged diff"] + Learn --> Reconcile{Reconcile against\ncurrent memory:\nadd, edit, or delete?} + Reconcile -->|no — common| Noop[Nothing to learn.\nMost merges teach\nnothing durable.] + Reconcile -->|yes| Route[Route each change to\nexactly one destination] + Route --> PR["learn/ PR\nyou review and merge"] +``` + +## The four destinations of a learned fact + +`/learn` is disciplined about *where* a fact lands. Every fact worth keeping routes +to **exactly one** place: + +| Destination | Use when | What it costs | +|---|---|---| +| **A lint** (`scripts/lints/*`) | The rule is mechanically checkable — pass/fail needs no judgment | Enforced on every PR forever; the error message doubles as a fix prompt | +| **Eager prose** (`AGENTS.md`) | It must be known *before* an agent would consult the Expert, and clears a strict bar | Paid every session — the high bar | +| **Lazy prose** (an Expert reference) | It is useful when *deliberately reasoning* about an area | Paid only when consulted — the usual home | +| **Nowhere** | It is inferable from the code, taste-only, or transient | — | + +Most facts go to the last two. A **nothing-to-learn** outcome is **common and +correct**, not a failure: vuln fixes, refactors that do not change shape, and +routine bug fixes usually change no memory at all. Preferring nothing over noise is +what keeps the Expert worth reading. + +## Lints: the memory an agent cannot ship past + +The top row of that table is the highest-value thing the harness can learn. A +**lint** is just a short script: glob some files, check a fact, exit non-zero with a +remediation message. It beats prose for two reasons: + +1. **The error message is a prompt.** It does not say "violation" — it says *how to + fix it*, feeding remediation straight into the agent's window so it + self-corrects. A prose rule is advice the agent *might* follow; a lint is a rule + it *cannot ship past*, plus the fix. +2. **It scales the way agents scale.** Once written, it applies to every file and + every future PR at once. + +So the most durable thing your project owns is the set of custom lints it grows +over time — layer-dependency direction, no raw SQL interpolation, +structured-logging-only, naming rules, file-size caps. Promotion is conservative: a +discovered invariant lives as prose first and is promoted to a lint only on +recurrence, and a drafted lint **must pass against the just-merged code** before it +is wired in. + +## Reconcile, don't accumulate + +Memory is a *current model of `main`*, not an append-only log. On every merge +`/learn` runs a three-pass reconcile against the merged diff: it **deletes** +references whose anchor code is gone, resolves **contradictions** between files that +now disagree, and **edits** claims the diff has invalidated. Adds, edits, and +deletes all ride the same `learn/` PR, each with a one-line justification +citing the diff hunk that motivated it — if it cannot be justified from the diff, it +is dropped. Inside the Expert, files are kept small and cross-linked with +`[[wikilinks]]`, so consulting memory never means loading all of it. + +## Related + +- [Continuous improvement](./continuous-improvement.md) — long-term memory is one + engine of the flywheel; this is why the harness compounds. +- [Spec-Driven Development](./spec-driven-development.md) — the short-term + counterpart, and where Reflect feeds long-term memory. +- [The human loop](./the-human-loop.md) — you are the third write path: you seed + memory deliberately, always through a merge. diff --git a/docs/concepts/output-contract.md b/docs/concepts/output-contract.md new file mode 100644 index 0000000..40a8219 --- /dev/null +++ b/docs/concepts/output-contract.md @@ -0,0 +1,90 @@ +# The output contract: ready-to-merge or STUCK + +The harness makes one promise: for every feature you start, you get back a pull +request in one of exactly two finished states — **ready to merge** or **STUCK with +a diagnosis**. This page covers how "done" is defined, how it is proven, and what +each terminal state means. It is the mechanics behind the guarantee introduced in +[harness engineering](./harness-engineering.md). + +## The definition of done is runnable + +The input to the harness is not just a prose description; it is a PRD paired with an +**executable definition of done**. `/intent` produces two coupled artifacts: + +- `prds//prd.md` — the prose: **why** this exists and **what** "done" + means; +- `prds//run-prd-test.sh` — the executable: **how you will know** it is + done. It exits 0 when the feature is built. + +The runner is the load-bearing idea, and it is what makes the harness +**goal-based**: the runner *is* the goal, and the loop keeps invoking the model +until the goal is met or the retry caps call it honestly unreachable. Prose drifts +and "done" becomes an argument; an exit code does not. + +Before `/intent` commits anything, it runs the script against today's unbuilt code +and confirms it fails **for the right reason** — because the behavior is genuinely +absent, not because of a typo or a missing dependency. That is the empirical proof +that the test actually corresponds to the intent. See +[Express intent](../how-to/express-intent.md) for how to write one. + +## Verification the agent cannot talk past + +Autonomy is only safe if "done" cannot be faked, so the harness leans on checks +that run **regardless of what the agent decides**, fastest to slowest: + +1. **Pre-commit hooks** — linters, formatters, type checks on changed files. +2. **Slice unit tests** — each slice's tests, run during implementation. +3. **`local-checks.sh`** — the cheapest gate before a PR: lint, typecheck, the fast + unit suite, skip-detection, and any custom project lints. It proves + **correctness, not coverage** — it blocks on real defects and merely warns on + style. +4. **The PRD runner** — `./prds//run-prd-test.sh` must exit 0. This is the + definition of done, and because it can mix deterministic shell checks with an + LLM-as-judge, "runnable" does not force everything into unit-test shape. + +The agent does not get to decide whether these run — they run, and the git/CI layer +enforces them independently. Crucially, **silencing a check counts as bypassing +it**: an agent may never add a suppression directive, weaken a config, or skip a +test to reach green. A check it cannot pass honestly is one it lets fail. + +## Ready to merge + +The first terminal state: the feature is built, every check passed, the PR is open +and the reviewer has no findings left. What is waiting for you is finished work you +never typed — ready for your judgment, not your typing. Evaluating it is the +[human loop](./the-human-loop.md)'s job, not the harness's. + +## STUCK + +Sometimes a feature genuinely cannot get through a step — a plan is subtly wrong, a +check will not pass honestly. The harness does not loop forever and will not fake +success. Every step has a bounded retry budget; when a step hits its cap, the +dispatcher declares the feature **STUCK**, posts a diagnostic to the PR, and halts +that feature until you step in. + +What it hands you is deliberate. Not just "it failed" — a session log of every +`claude -p` invocation across the chain (so you can open any trace and see what the +agent saw), a tail of the failing output, and a **diagnosis-first checklist**. The +checklist's first item is not "fix the code." It is *identify which piece of context +misled the agent* — a stale Expert note, a thin spec, a PRD that left something out +— and correct that first. Because if the context that caused the failure stays +wrong, the same class of failure comes back the next time a feature touches that +area. See [Unstick a feature](../how-to/unstick-a-feature.md). + +## Both states are finished — and the ratio is your metric + +Ready-to-merge and STUCK are **both finished states**: the system completed its run +and told you the truth about which one you got. It never returns "maybe." + +The ratio between them is the number to watch. Every STUCK names a piece of context +to improve, and every improvement raises the odds the next feature comes back +ready. Driving that ratio up over time is [continuous improvement](./continuous-improvement.md) +— the reason the harness is worth tuning rather than just running. + +## Related + +- [Harness engineering](./harness-engineering.md) — where the guarantee comes from. +- [The dispatcher](./the-dispatcher.md) — the engine that drives every feature to + one of these two states. +- [Design invariants](../reference/invariants.md) — the proof the verification + layers cannot be talked past. diff --git a/docs/concepts/spec-driven-development.md b/docs/concepts/spec-driven-development.md new file mode 100644 index 0000000..43f1fe4 --- /dev/null +++ b/docs/concepts/spec-driven-development.md @@ -0,0 +1,114 @@ +# Spec-Driven Development: the harness's short-term memory + +Spec-Driven Development (SDD) is how the harness builds one feature well. It is +best understood as **[context engineering](./context-engineering.md) applied to a +single feature** — and as the harness's **short-term memory**: a point-in-time +plan for one feature, not a durable store of project knowledge. + +## SDD is a context-engineering technique + +Give an agent "add search to the app" and it does something reasonable: it greps, +opens files to infer conventions, guesses how you test. On a small change that is +fine. On a large feature it accumulates — halfway through, the window is full of +half-relevant code the agent retrieved on its own, the original intent has decayed, +and the next compaction is poised to drop the part it actually needed. + +SDD fixes this by doing the thinking **outside** the context window first and +persisting it as structured files on disk. The plan does not sit in the +conversation where it decays; it sits in files the agent pulls from. That is the +core context-engineering move: **the right context reaches the window at the right +time because the agent dynamically pulls the slice it needs, rather than carrying +the whole feature in-window the entire way.** The plan cannot decay or compact +away, because it was never in the conversation to begin with — after a compaction +the agent simply re-reads the spec and continues. + +## Short-term memory, not long-term memory + +This is the distinction that keeps the two memory systems from blurring: + +> A spec is **short-term memory**: it exists to build **one feature**, and it is +> a **point-in-time** artifact. It is not where the project's durable knowledge +> lives. + +While the feature is being built, the spec is the agent's working memory — +focused entirely on this one feature, disclosed a slice at a time. Once the +feature is complete, the spec **stops steering anything**. It does not roll up +into a growing knowledge base. Its remaining value is as a *record*: + +- **Reviewing the code** — the spec says what was intended, so a reviewer can + check the diff against it. +- **Evals** — a completed spec and its build trail are raw material for capturing + regression checks over the harness's own behavior. +- **Understanding the agent's decisions** — when you want to know *why* the agent + built it this way, the spec is the reasoning it worked from. + +Durable, cross-feature knowledge — architecture, patterns, hard-won constraints — +does not belong in a spec. That is [long-term memory](./long-term-memory.md), and +it lives in the Expert. Keeping short-term and long-term memory separate is what +lets each do its job: the spec stays lean and disposable; the Expert stays curated +and permanent. + +## The artifacts SDD produces + +When [`/spec-planning`](../../skills/sdd/spec-planning/SKILL.md) runs, the planner +researches the actual codebase (grounding the plan in reality, not guesswork), +pulls in any Experts whose triggers match, and writes the plan to disk as two +kinds of file: + +- a **mainspec** (`specs//mainspec.md`) — the complete end state, the + north star you work backward from; +- ordered **slices** (`specs//slices/`) — temporal chunks of intent, each + a coherent unit of work focused on *what* and *why*. + +What goes *into* a spec is itself disciplined context engineering — precise +BEFORE/AFTER file paths, type contracts first, DO/DON'T counterexamples, narrative +temporal flows, and forward-looking requirements — so the agent can execute +without guessing. + +## Temporal slicing: progressive disclosure, structurally + +Slices are ordered by *intent* (what needs to happen), not by *component* +(frontend/backend), because features have a natural dependency order and slicing +by intent preserves it. Each slice depends on prior slices and declares contracts +for future ones. + +That ordering does two jobs at once. For the implementer it is progressive +disclosure made structural: the agent is fed **only the current slice**, never the +whole feature, so its window stays small and focused. For the orchestrator, the +dependencies define execution order — every mainspec carries a **Slice Dependency +Map** that says which slice to implement next. + +## Validation: consensus before code + +A plan has blind spots, so +[`/spec-validate`](../../skills/sdd/spec-validate/SKILL.md) hardens it before a +line of code is written: multiple independent Opus subagents review the spec, and +agreement is graded (3/3 = very high confidence, down to 1/3 = a judgment call). +Relevant Experts add domain-specific review. Findings are consolidated and the +impactful ones applied **in place** — validation sharpens the plan, it does not +bounce it back to start over. Independent reviewers have *different* blind spots; +consensus scoring turns that into a confidence signal instead of a coin flip. + +## Implementation: write, verify, reflect + +[`/implement-slice`](../../skills/sdd/implement-slice/SKILL.md) implements one +slice in three beats: write the code, verify it with unit tests, then **Reflect**. +Reflect is the one that reaches *out* of short-term memory: once the code is green, +the agent compares what it just learned against the project's long-term memory and +— only when there is a real, durable lesson — writes it back into the Expert. This +is the one bridge from a feature's short-term memory to the project's long-term +memory, and the bar is deliberately high; most slices reflect nothing. + +[`/implement-mainspec`](../../skills/sdd/implement-mainspec/SKILL.md) orchestrates +the whole feature: it reads the Slice Dependency Map and delegates each slice, in +dependency order, to a focused subagent — committing each to the feature branch as +it lands. One slice at a time keeps the orchestrator's window lean and every +commit reviewable. + +## Related + +- [Context engineering](./context-engineering.md) — the lever SDD applies. +- [Long-term memory](./long-term-memory.md) — the durable counterpart; where + Reflect writes. +- [The dispatcher](./the-dispatcher.md) — runs the SDD loop autonomously, one step + per fresh window. diff --git a/docs/concepts/the-dispatcher.md b/docs/concepts/the-dispatcher.md new file mode 100644 index 0000000..0789715 --- /dev/null +++ b/docs/concepts/the-dispatcher.md @@ -0,0 +1,105 @@ +# The dispatcher: the deterministic engine + +The dispatcher is the deterministic control flow at the center of the harness. It +is the piece that makes a run repeatable, crash-safe, and trustworthy to leave +unattended — because it holds **no LLM in the decision path** and **no hidden +state**. + +## Artifacts are the state + +The reason it is safe to leave the harness running is almost boring, and that is +the point. **The harness keeps no hidden state.** There is no daemon holding "I am +currently on step 3" in memory, no queue, no coordination service. The complete +state of every feature is observable from two things: the files on disk and the +branches in git. + +A small bash script — the dispatcher +([`scripts/poll-and-dispatch.sh`](../../scripts/poll-and-dispatch.sh)) — wakes up +periodically, takes an environment as its argument, reads that environment's state +fresh, and decides the single next step for each active feature. Its core is an +`if/elif` chain: *planning output absent? run planning. Present but validation +absent? run validate.* The chain **is** the state machine; the artifacts on disk +**are** the state. + +A feature advances as a sequence of states, each produced by one skill and +detected by the presence of its output on disk: + +```mermaid +flowchart TD + Intent["/intent (you, once)\nPRD + runnable definition of done"] --> Claim[Harness claims the work] + Claim --> Plan["/spec-planning"] + Plan --> Validate["/spec-validate"] + Validate --> Implement["/implement-mainspec"] + Implement --> Checks["local-checks.sh"] + Checks --> PR[Open pull request] + PR --> Review[Reviewer posts findings] + Review -->|findings| Respond["/address-feedback"] + Respond --> Review + Review -->|no findings left| Ready[Ready for your review] + Ready --> You([You merge]) +``` + +## Three properties that make it trustworthy + +Three consequences fall out of "artifacts are the state," and together they are +why the machine is safe to run: + +- **Crash recovery is free.** Kill the dispatcher mid-step — `kill -9`, a dead + laptop, a closed lid. The next tick re-reads disk, sees the half-finished state, + and resumes. Nothing to clean up, because nothing was ever held in memory to + lose. +- **Every step runs in a fresh context window.** The dispatcher does not *do* the + work; it shells out to a brand-new `claude -p` process per skill. Each skill + reads what it needs from disk, does its job, writes its output, and exits. No + step inherits another's polluted window — the + [context-engineering](./context-engineering.md) problem, solved by construction. + This is also why the loop can run for hours without the context rot a single + long session accumulates. +- **The dispatcher itself contains no LLM.** The decision of *what runs next* is + pure, deterministic bash. The intelligence is in the skills; the routing is + mechanical. That is what makes "what will it do next?" answerable just by looking + at disk — no model in the loop to second-guess. + +## It never touches your checkout + +The property developers ask about first: **the harness never touches your working +tree.** It operates on your clone only through git *refs* — fetching, pushing, +claiming branches — and does all its work in *sibling worktrees* +(`-harness-`) it creates and tears down itself. Your uncommitted +work is structurally out of its reach. + +## Scheduling is one exit code + +The dispatcher does not schedule itself; a supervisor (or cron, or a server +runner) invokes it, and the dispatcher reports what happened through its **exit +code**: + +- **0 — idle.** No work advanced. Sleep the interval (default 5 minutes) and tick + again. +- **10 — work advanced.** Re-invoke immediately, so a claimed PRD marches through + planning → validate → implement at machine speed instead of one step per nap. +- **non-zero error** — back off exponentially. + +A STUCK feature reports idle, so a stuck environment never hot-loops. This one +exit code is the entire scheduling protocol; see [Run the harness](../how-to/run-the-harness.md) +for the CLI that drives it. + +## The branch namespace is the work queue + +There is no separate database of "what work exists." The branches *are* the +registry, and claiming work is a single atomic git rename — no lock service, no +coordination daemon. The full namespace and on-disk state layout are documented in +[Reference: state and branches](../reference/state-and-branches.md). + +## The rigorous version + +This page gives you the intuition. For the precise properties the harness holds +under concurrency, crashes, and restarts — and the proof it is safe to leave +running — see the [design invariants](../reference/invariants.md). + +## Related + +- [Harness engineering](./harness-engineering.md) — the discipline this engine + realizes. +- [The output contract](./output-contract.md) — the guaranteed output the + dispatcher drives toward, and the verification that backs it. diff --git a/docs/concepts/the-human-loop.md b/docs/concepts/the-human-loop.md new file mode 100644 index 0000000..f07b912 --- /dev/null +++ b/docs/concepts/the-human-loop.md @@ -0,0 +1,128 @@ +# The human loop + +Once the machine does the typing, what is left is the part only you can do — and it +is the most important part, not the leftover. The human loop is you, deliberately +working the judgment a harness structurally cannot supply. + +## Outsource your thinking, not your understanding + +The governing line comes from Andrej Karpathy: *"you can outsource your thinking but +you can't outsource your understanding."* It draws a sharp boundary: + +- **Verifiable work → outsource it freely.** Syntax, API recall, implementation + mechanics. The model is superhuman here; spending your attention on it is waste. +- **Unverifiable work → you must own it.** Whether this is the right thing to + build, whether the abstraction is sound, whether the edge cases are handled for + good reasons, whether the UX feels right. Errors here are subtle and do not + announce themselves — exactly where your understanding has to be load-bearing. + +The harness took the first category. The human loop is you, deliberately working +the second. + +## Three phases, one cycle + +``` + Understanding ──▶ Intent ──▶ [ the harness builds ] ──▶ Evaluate + build your model express the machine loop walk the result, + of the problem what to run it, judge it, + space build improve the context + ▲ │ + └──────────── evaluating deepens understanding ──────────┘ +``` + +The human loop and the machine loop are not parallel tracks — they feed each other: + +> **Your loop's output is the harness's input. The harness's output is your loop's +> input.** + +You produce intent (a PRD); the harness consumes it and produces a pull request; +you consume that PR by evaluating it; what you learn sharpens the next intent. +Naming your loop explicitly is what keeps *your* job legible as the machine takes +over more of the typing. + +## Understanding — `/wiki-init` + +Before you can express good intent, you need a real model of the problem space: the +domain, the prior art, the constraints, the trade-offs. +[`/wiki-init`](../../skills/human-loop/wiki-init/SKILL.md) stands up a standalone, +LLM-maintained knowledge base in the shape of Karpathy's "LLM Wiki": you synthesize +**once, at ingest time**, into durable, cross-linked pages that compound as sources +accumulate. You curate sources and ask questions; the LLM does the bookkeeping +humans abandon wikis over. + +This wiki is deliberately **not** a project artifact — hold this bright line: + +- The **wiki** is cross-project **domain and architecture** knowledge, written to + be read **by you**. It lives in its own repo, outside any codebase. +- The **Expert** ([long-term memory](./long-term-memory.md)) is per-project **code** + memory, written to be read **by agents**. + +A richer model of the domain means a sharper `/intent`. + +## Intent — `/intent` + +[`/intent`](../../skills/human-loop/intent/SKILL.md) is where understanding becomes +a buildable thing. Its discipline: + +- **Elicit outcomes, not solutions.** People arrive describing a solution ("add a + `/api/search` endpoint"); the job is to surface the *need* underneath ("readers + can't find a post by title") and the observable outcome that would satisfy it. +- **"How would we know that's true?"** is the throughline. Asked of every desired + outcome, it converts a wish into both a sharp prose criterion *and* a concrete + check — the coupled `prd.md` + `run-prd-test.sh` born together (see the + [output contract](./output-contract.md)). +- **You don't write the runner; the Expert drafts it, you review.** This keeps + verification grounded in how the project actually works. + +`/intent` is a coordinator, not a knowledge holder — the domain reasoning comes from +the Expert; your contribution is understanding and the judgment about what is worth +building. See [Express intent](../how-to/express-intent.md). + +## Evaluate — `/evaluate-pr` and `/evaluate-sessions` + +The back bookend, and the mirror of `/intent`. There are two skills, because there +are two things to evaluate. + +- **[`/evaluate-pr`](../how-to/evaluate-a-pr.md)** — evaluate *what was built*. The + tangible output is merge, fix-and-push, or close; the output that matters more is + *you* understanding the change deeply enough to defend every decision in it. The + bot reviewer already caught the mechanical defects, so this skill sets those aside + and spends your attention on what a bot cannot judge — is this simpler than it + could be, is the abstraction sound, does the UX feel right? If the walk surfaces + something to change, **you fix it here and push** — you never hand work back to + the loop. You are the last mile. +- **[`/evaluate-sessions`](../how-to/improve-from-traces.md)** — evaluate *how it + was built*. This is where the human loop reaches back and improves the harness + itself, reading the `claude -p` build trail to find where context served the + agents or failed them, and freezing what you find as evals and context fixes. This + is the heart of [continuous improvement](./continuous-improvement.md). + +## Memory still has one write path + +Evaluation does *not* write memory directly. Whatever you learn here is not ground +truth yet, because the change is not merged yet. So the insight either becomes a +pushed fix that rides into `main` — where `/learn` picks it up — or it lives in your +head and sharpens the next Intent. Evals and context fixes land on a branch and +reach memory the same way: through a merge. You may now *seed* memory deliberately; +you still never bypass the door. See [long-term memory](./long-term-memory.md#one-write-path-ground-truth-only). + +## The three places you steer + +Across the whole system you touch the machine at exactly three points — and every +one is a phase of this loop: + +| You... | Human-loop phase | What it does to the machine | +|---|---|---| +| Confirm a PRD | end of **Intent** | starts the build | +| Evaluate and merge a PR | **Evaluate** | ends the build; triggers `/learn` | +| Unstick a STUCK feature | a forced detour into **Evaluate** | corrects the context, then merges | + +Three touchpoints. Everything between them is the machine. Everything *at* them is +judgment — yours. + +## Related + +- [Continuous improvement](./continuous-improvement.md) — evaluation is how you + drive the flywheel. +- [Harness engineering](./harness-engineering.md) — what the machine half + guarantees, so you can spend your attention here. diff --git a/docs/concepts/two-tier-architecture.md b/docs/concepts/two-tier-architecture.md new file mode 100644 index 0000000..f15a514 --- /dev/null +++ b/docs/concepts/two-tier-architecture.md @@ -0,0 +1,77 @@ +# The two-tier architecture: one harness, N environments + +Context Specs is not something you install into a project. It is its own repo — +**the harness repo** — that operates on any number of project repos, called +**environments**. This two-tier split is the structural heart of the system. + +``` +HARNESS REPO (tier 1 — yours, one) ENVIRONMENT REPOS (tier 2 — your projects, many) + bin/context-specs the CLI AGENTS.md the eager contract + scripts/ the dispatchers .claude/skills/intent/ project-owned /intent + skills/ canonical skills .claude/skills/expert/ long-term memory + state// runtime state scripts/ bootstrap + local checks + .harness/env this env's dials +``` + +You maintain **one** harness repo. It drives **many** environments — so working on +several projects at once is the default, not a special mode. Improve something in +the harness repo and every environment inherits it at once. + +## The dividing line: could you write it without reading the project's code? + +Every artifact in the system lands on one side of a single test: + +> **Could you write it without reading the project's code?** + +- **Yes → it belongs in the harness repo.** The CLI, the dispatchers, the + canonical skills. These are project-agnostic; improving one improves every + environment. +- **No → it is Software 3.0.** It has to be generated by a model reading *that* + project, committed to *that* project, and evolved with it. An `AGENTS.md` that + describes this codebase's conventions, an `/intent` skill tuned to how this team + expresses features, the project's Expert — none can be written in the abstract. + +The phrase **Software 3.0** names this second category: code and context that are +authored by a model reading a specific project rather than typed by a human or +shipped by a framework. The two-tier split is what keeps the shared, reusable half +cleanly separated from the per-project, generated half. + +## How the tiers meet: symlinks and generation + +Two mechanisms connect the tiers: + +- **`context-specs add `** registers a project as an environment and + **symlinks** the canonical skills from the harness repo into the environment's + `.claude/skills/` (gitignored — they are the harness's, not the project's). This + is the deterministic half of setup. See [Add an environment](../how-to/add-an-environment.md). +- **`/env-init`** runs *inside* the environment and generates the Software 3.0 + half — the `AGENTS.md`, the project-owned `/intent`, the Expert skeleton, the + checks, the bootstrap. See [Initialize a project](../how-to/initialize-a-project.md). + +Setup itself demonstrates the discipline: the CLI does the deterministic, +project-agnostic part, then a skill reads the project and generates the part that +can only come from reading it. + +## The two developer-owned levers + +Most canonical skills are symlinked in and left alone. Two artifacts are +deliberately **project-owned** rather than shared, because they are the two levers +that most determine how well the harness serves a given project: + +- **`/intent`** — the input side. How well a project turns an open-ended idea into + a PRD plus a runnable definition of done is one of the biggest levers it has. + It ships as a committed copy you tune to your project, not a symlink. See + [Express intent](../how-to/express-intent.md). +- **The Expert** — the memory side. The project's [long-term memory](./long-term-memory.md), + which informs every future plan. The loops file lessons into it; you shape it. + +These are the two places your judgment lives in the environment. Everything else +the harness brings with it. + +## Related + +- [Harness engineering](./harness-engineering.md) — why the system has this shape. +- [The dispatcher](./the-dispatcher.md) — how one harness drives an environment, + step by step. +- [Reference: state and branches](../reference/state-and-branches.md) — the exact + on-disk layout of both tiers. diff --git a/docs/how-to/add-an-environment.md b/docs/how-to/add-an-environment.md new file mode 100644 index 0000000..fbdcbed --- /dev/null +++ b/docs/how-to/add-an-environment.md @@ -0,0 +1,55 @@ +# Add an environment + +Registering a project as an **environment** connects it to your harness. This is +the deterministic half of setup — the CLI does it without reading your project's +code. + +## Prerequisites + +- A [harness repo](./create-a-harness.md). +- A target project that is a git repository. + +## Steps + +From inside your harness repo: + +```bash +context-specs add ~/code/myapp # or: add ~/code/myapp --name myapp +``` + +`add` does three project-agnostic things: + +1. **Symlinks the canonical skills** from the harness repo into the project's + `.claude/skills/` (gitignored — they belong to the harness, not the project). +2. **Writes `.gitignore` entries** so those symlinks and the harness's runtime + artifacts stay out of the project's history. +3. **Registers the project** in the harness's `environments.toml`. + +Two skills are deliberately *not* symlinked, because they are the project's own +[developer-owned levers](../concepts/two-tier-architecture.md#the-two-developer-owned-levers): +`/intent` and the Expert. Those are generated into the project in the next step. + +## Verify + +```bash +context-specs doctor +``` + +The project should now appear as a registered environment. + +## Re-linking + +The skill symlinks live in worktrees the harness creates and tears down, so they +are re-created automatically by `bootstrap-worktree.sh`. If you ever need to +recreate them by hand (e.g. in a fresh clone), run: + +```bash +context-specs link ~/code/myapp +``` + +`link` is idempotent. + +## Next + +- [Initialize a project](./initialize-a-project.md) — generate the Software 3.0 + half (`AGENTS.md`, `/intent`, the Expert, checks). diff --git a/docs/how-to/create-a-harness.md b/docs/how-to/create-a-harness.md new file mode 100644 index 0000000..9975061 --- /dev/null +++ b/docs/how-to/create-a-harness.md @@ -0,0 +1,37 @@ +# Create a harness + +The harness repo is the one repo you maintain that drives all your projects. You +create it once. + +## Prerequisites + +- Node.js (for `npx`). +- `git`, and the `claude` CLI on your `PATH`. + +## Steps + +Create (or adopt) a harness repo from the template: + +```bash +npx context-specs init my-harness +cd my-harness +``` + +`init` scaffolds the [two-tier layout](../concepts/two-tier-architecture.md): the +`context-specs` CLI under `bin/`, the dispatchers under `scripts/`, the canonical +skills under `skills/`, and an empty `state/` for per-environment runtime data. If +you point `init` at an existing repo, it *adopts* it — adding the harness pieces +without disturbing what is already there. + +## Verify + +```bash +context-specs doctor +``` + +`doctor` checks the harness itself, the registry, and every registered environment. +On a fresh harness it should report a healthy harness with no environments yet. + +## Next + +- [Add an environment](./add-an-environment.md) — register your first project. diff --git a/docs/how-to/evaluate-a-pr.md b/docs/how-to/evaluate-a-pr.md new file mode 100644 index 0000000..25f2b60 --- /dev/null +++ b/docs/how-to/evaluate-a-pr.md @@ -0,0 +1,57 @@ +# Evaluate a PR + +When the harness hands back a **ready-to-merge** PR, evaluating it is your job — the +[unverifiable work](../concepts/the-human-loop.md#outsource-your-thinking-not-your-understanding) +the machine could not do. `/evaluate-pr` is a teacher and a taste partner, not a +second linter. + +## Prerequisites + +- A ready PR from the harness. +- You are running `claude` inside the project. + +## Steps + +```bash +cd ~/code/myapp +claude +> /evaluate-pr +``` + +[`/evaluate-pr`](../../skills/human-loop/evaluate-pr/SKILL.md) produces two outcomes: + +- **The tangible one:** merge, fix-and-push, or close. +- **The one that matters more:** *you* understanding the change deeply enough to + defend every scenario and design decision in it. + +Because the bot reviewer already caught the mechanical defects, the skill *ingests* +those findings and sets them aside, then spends your attention on what a bot +structurally cannot judge: + +- Is this simpler than it could be? +- Is the abstraction sound? +- Does the UX feel right? + +It runs the system with you, walks the definition-of-done scenarios live, and probes +Socratically rather than lecturing. The understanding gate is soft but real: it ends +on "do you feel you understand this change?" and skipping the walk-through is an +explicit opt-out, never a silent rubber-stamp. + +## If you find something to change + +**Fix it here and push.** You never hand work back to the loop — you are the last +mile. Whatever you fix rides into `main` on the merge, where +[`/learn`](../concepts/long-term-memory.md) picks it up as ground truth. + +## Why this closes the loop + +The understanding you build here is the literal mechanism that sharpens your next +[intent](./express-intent.md) — evaluating deepens understanding, which produces +better intent, which the harness builds. When you evaluate, you do not just approve +work; you improve the thing that produced it. + +## Related + +- [Improve from build traces](./improve-from-traces.md) — evaluate *how* it was + built, not just what. +- [The human loop](../concepts/the-human-loop.md) — where this phase sits. diff --git a/docs/how-to/express-intent.md b/docs/how-to/express-intent.md new file mode 100644 index 0000000..66a2061 --- /dev/null +++ b/docs/how-to/express-intent.md @@ -0,0 +1,58 @@ +# Express intent + +`/intent` is how you turn an idea into work the harness can build. It produces a +PRD paired with a **runnable definition of done** — the harness's input and its +goal. This is one of the three places [you steer the machine](../concepts/the-human-loop.md#the-three-places-you-steer). + +## Prerequisites + +- The project is [initialized](./initialize-a-project.md) (`/intent` and the Expert + exist). +- You are running `claude` inside the project. + +## Steps + +```bash +cd ~/code/myapp +claude +> /intent +``` + +Then describe what you want. [`/intent`](../../skills/human-loop/intent/SKILL.md) +will: + +1. **Elicit the outcome, not the solution.** If you describe an implementation + ("add a `/api/search` endpoint"), it surfaces the need underneath ("readers + can't find a post by title") and the observable outcome that would satisfy it. +2. **Ask "how would we know that's true?"** of each outcome, converting a wish into + a sharp prose criterion *and* a concrete check. +3. **Draft the runner for you.** You do not write `run-prd-test.sh` — the Expert + drafts it so verification is grounded in how the project actually works, and you + review it. +4. **Confirm the test fails for the right reason.** Before committing, `/intent` + runs the script against today's unbuilt code and checks that it fails because the + behavior is *genuinely absent* — not because of a typo or missing dependency. + +## What you get + +Two coupled artifacts on a `prd//` branch: + +- `prds//prd.md` — why it exists and what "done" means. +- `prds//run-prd-test.sh` — the executable definition of done; exits 0 when + the feature is built. + +The moment you confirm the PRD, it lands on the queue branch and the harness can +claim it. See [the output contract](../concepts/output-contract.md) for how that +runner becomes the goal the loop drives toward. + +## Tips + +- **Spend your judgment here.** How well a project turns an idea into a good PRD is + one of the biggest levers it has. A thin definition of done is the most common + cause of a STUCK later. +- **Tune the skill.** `/intent` is project-owned; adjust it to how your team + actually expresses features. + +## Next + +- [Run the harness](./run-the-harness.md) — let the loop build it. diff --git a/docs/how-to/improve-from-traces.md b/docs/how-to/improve-from-traces.md new file mode 100644 index 0000000..cdbeb23 --- /dev/null +++ b/docs/how-to/improve-from-traces.md @@ -0,0 +1,62 @@ +# Improve the harness from build traces + +`/evaluate-sessions` is where you evaluate *how* a feature was built, not just what +was built — and turn what you find into durable improvements to the harness itself. +This is the engine of [continuous improvement](../concepts/continuous-improvement.md). + +## Prerequisites + +- A PR the harness built (its `claude -p` build trail is posted on the PR). +- You are running `claude` inside the project. + +## Steps + +```bash +cd ~/code/myapp +claude +> /evaluate-sessions +``` + +[`/evaluate-sessions`](../../skills/human-loop/evaluate-sessions/SKILL.md) reads the +build trail *with you* to find where the project's context served the agents and +where it failed them — where an agent re-derived something the Expert should have +told it, followed a stale `AGENTS.md` pointer, or guessed because a spec was thin. + +## The two durable outcomes + +What you find turns into two things, both of which persist: + +- **Evals** — when a session shows a skill behaved well or badly *given the context + it had*, freeze that as a runnable check under `evals/`. An eval is a regression + test over the harness's **own skills and context** (the analog of testing a + prompt), distinct from the PRD runner, which tests the product. +- **Context fixes** — when a piece of context misled an agent, fix the Expert + reference, the `AGENTS.md` pointer, or the skill. + +The shape is always the same: + +> *Observe a trace → capture it as an eval → fix the context → it persists as a +> regression test.* + +## How it reaches memory + +Evals and context fixes are not ground truth until merged, so they land on a branch +and reach memory the same way everything else does — through a merge, where +[`/learn`](../concepts/long-term-memory.md#one-write-path-ground-truth-only) picks +them up. You may *seed* memory deliberately here; you still never bypass the single +write path. + +## Why it matters + +Every PR the harness builds is a graded trial of your project's context. You are not +auditing one PR — you are **tuning the harness**, and every eval you capture makes +the project a little better at building itself next time. That is what drives the +[ready-to-merge ratio](../concepts/continuous-improvement.md#the-metric-the-ready-to-merge-ratio) +up over time. + +## Related + +- [Continuous improvement](../concepts/continuous-improvement.md) — the flywheel + this feeds. +- [Evaluate a PR](./evaluate-a-pr.md) — the companion skill: evaluate *what* was + built. diff --git a/docs/how-to/initialize-a-project.md b/docs/how-to/initialize-a-project.md new file mode 100644 index 0000000..d39f241 --- /dev/null +++ b/docs/how-to/initialize-a-project.md @@ -0,0 +1,41 @@ +# Initialize a project + +After a project is [registered](./add-an-environment.md), it still needs the +**Software 3.0** half — the pieces that can only be written by a model reading +*this* project. `/env-init` generates them. + +## Prerequisites + +- The project is registered as an environment. +- You are running `claude` inside the project directory. + +## Steps + +From inside the project: + +```bash +cd ~/code/myapp +claude +> /env-init +``` + +[`/env-init`](../../skills/harness/env-init/SKILL.md) reads the codebase and +generates the project-owned artifacts as a single PR: + +- **`AGENTS.md`** — the eager contract: a short map that points into the Expert + (see [long-term memory](../concepts/long-term-memory.md)). +- **`/intent`** — a committed, project-tuned copy of the intent skill. +- **The Expert skeleton** — the project's [long-term memory](../concepts/long-term-memory.md), + seeded and ready to grow. +- **`scripts/`** — the bootstrap and `local-checks.sh` gate. + +## Review and merge + +`/env-init` opens its work as a pull request. **Review and merge it** before +starting the harness — this is generated project code, and it is the foundation +every future feature builds on. Treat it like any other PR. + +## Next + +- [Express intent](./express-intent.md) — describe your first feature. +- [Run the harness](./run-the-harness.md) — start the loop and walk away. diff --git a/docs/how-to/run-the-harness.md b/docs/how-to/run-the-harness.md new file mode 100644 index 0000000..40b62d8 --- /dev/null +++ b/docs/how-to/run-the-harness.md @@ -0,0 +1,64 @@ +# Run the harness + +Once a project is [initialized](./initialize-a-project.md) and has at least one +[PRD](./express-intent.md) on the queue, the harness can build unattended. This +guide covers the CLI that schedules [the dispatcher](../concepts/the-dispatcher.md). + +## Start the loop and walk away + +```bash +context-specs start # this environment +context-specs start --all # every registered environment +``` + +`start` runs one background supervisor per environment — a **build loop** and a +**memory loop**. Each environment gets its own supervisor, lock, and state, so +running several projects at once is the default, not a mode. + +The scheduling protocol is just the dispatcher's exit code: **0** means idle (sleep +the interval, default 5 minutes), **10** means "work advanced" (re-invoke +immediately, so a claimed PRD marches through planning → validate → implement at +machine speed). Errors back off exponentially, and a STUCK feature reports idle so a +stuck environment never hot-loops. + +Stop them with: + +```bash +context-specs stop # or: stop --all +``` + +## Run one pass in the foreground + +When you would rather watch than daemonize: + +```bash +context-specs run # one tick, drained to idle, no daemon +context-specs run --learn # run the memory loop instead of the build loop +``` + +## Observe + +```bash +context-specs status # one table: every environment's features and phases +context-specs status --fetch # fetch refs first, then show +context-specs logs myapp -f # follow the build loop +context-specs logs myapp --learn # the memory loop's logs +context-specs doctor # check the harness, registry, and every environment +``` + +`status` applies the dispatcher's liveness gate — it shows active features, not +ones already merged or closed. + +## What comes back + +Every feature ends in one of two states — **ready to merge** or **STUCK** — per +[the output contract](../concepts/output-contract.md). From here: + +- A ready PR → [evaluate it](./evaluate-a-pr.md). +- A STUCK feature → [unstick it](./unstick-a-feature.md). + +## Scaling beyond a laptop + +The dispatcher is the portable part: the same script a laptop supervisor invokes +can be driven by cron or a server runner. When a team outgrows local laptops, they +move the *scheduler* and keep everything else — an upgrade path, not a rewrite. diff --git a/docs/how-to/unstick-a-feature.md b/docs/how-to/unstick-a-feature.md new file mode 100644 index 0000000..96c840a --- /dev/null +++ b/docs/how-to/unstick-a-feature.md @@ -0,0 +1,49 @@ +# Unstick a feature + +When a feature cannot get through a step honestly, the harness declares it +**STUCK**, posts a diagnostic to the PR, and halts that feature. STUCK is a +*finished* state, not a crash — the system told you the truth instead of faking +success. Unsticking it is a forced detour into the [Evaluate phase](../concepts/the-human-loop.md), +and it is one of the three places you steer the machine. + +## What the harness hands you + +A STUCK PR comes with everything you need to diagnose it: + +- A **session log** of every `claude -p` invocation across the chain — open any + trace and see exactly what the agent saw. +- A **tail of the failing output**. +- A **diagnosis-first checklist**. + +## Steps + +Work the checklist in order — and note that its first item is *not* "fix the code": + +1. **Identify which piece of context misled the agent.** A stale Expert note, a + thin spec, a PRD that left something out, an environment the agent could not + navigate. Read the trace to find where it went wrong. +2. **Fix that context first.** Correct the Expert reference, sharpen the + definition of done, add the missing detail. This is the + [context-gap fix](../concepts/continuous-improvement.md#two-ways-to-fix-a-problem-very-different-leverage) + that stops the *class* of failure, not just this instance. +3. **Then make the feature pass** on its branch, honestly — never by silencing a + check. +4. **Merge.** + +## Why the order matters + +If the context that caused the failure stays wrong, the same class of failure comes +back the next time a feature touches that area. Fixing the code fixes one feature; +fixing the context fixes the class. + +Because you correct the context *on the feature branch* and merge it, that +correction is in the diff [`/learn`](../concepts/long-term-memory.md) reads — so your +hand fix becomes permanent project memory automatically. Every STUCK you resolve +this way raises the [ready-to-merge ratio](../concepts/continuous-improvement.md#the-metric-the-ready-to-merge-ratio). + +## Related + +- [The output contract](../concepts/output-contract.md) — what STUCK means and why + the harness refuses to fake success. +- [Continuous improvement](../concepts/continuous-improvement.md) — why the + context-first order compounds. diff --git a/docs/overview.md b/docs/overview.md new file mode 100644 index 0000000..1525923 --- /dev/null +++ b/docs/overview.md @@ -0,0 +1,93 @@ +# How Context Specs works + +This is the narrative tour — the through-line that connects the +[core concepts](./README.md#core-concepts) in one reading. If you prefer to jump +straight to a concept or a task, use the [documentation map](./README.md). If you +want the whole idea in one sitting, read on. + +## The one idea + +Context Specs is [harness engineering](./concepts/harness-engineering.md) applied to +building software. An **agent is a model plus a harness** — the model supplies +probabilistic intelligence, the harness supplies deterministic control. Harness +engineering is building a system with defined inputs and defined outputs, where the +deterministic code invokes the probabilistic code and drives the flow all the way to +a guaranteed output. + +Here the input is a PRD with a runnable definition of done. The output is **a pull +request that is either ready to merge or STUCK with a diagnosis** — never a guess. +That output is also the system's feedback signal, and improving the ratio between +the two is the whole game. + +## The lever underneath everything + +Every part of the system is an application of one lever: +[context engineering](./concepts/context-engineering.md) — controlling what enters an +agent's context window, and what stays out. The window is finite and it degrades +(decay, pollution, compaction), so the discipline is to externalize durable +knowledge to the filesystem and let the agent pull just what it needs, just in time. +Watch that same lever get pulled at larger and larger scope as the story goes on. + +## Building one feature: short-term memory + +The smallest unit of work is a feature. +[Spec-Driven Development](./concepts/spec-driven-development.md) is context +engineering applied to one feature: think outside the window first, and persist the +plan as a **mainspec** plus ordered **slices** on disk. The agent is fed one slice +at a time, so its window stays small and the plan can't decay or compact away. A +spec is the harness's **short-term memory** — a point-in-time plan for one feature, +disposable once the feature ships. It is *not* where durable knowledge lives. + +## Running it unattended: the machine + +[The dispatcher](./concepts/the-dispatcher.md) takes that feature loop and runs it +autonomously. It can be trusted unattended because it keeps **no hidden state**: +every feature's state is observable from files on disk and branches in git. A small +deterministic bash script reads that state each tick and shells out to a fresh +`claude -p` process per step — so no step inherits another's polluted window, crash +recovery is free, and there is **no LLM in the decision path**. It never touches your +checkout; it works your repo's refs and its own sibling worktrees. + +What makes "done" trustworthy is [the output contract](./concepts/output-contract.md): +a runnable definition of done the agent cannot argue with, backed by verification +layers it cannot talk past. When a feature can't finish honestly, the harness stops +and hands you a diagnosis — **STUCK** — instead of faking success. This all runs +across [one harness driving N environments](./concepts/two-tier-architecture.md), +split cleanly between the project-agnostic harness repo and the Software 3.0 pieces +generated per project. + +## Getting better every merge: the flywheel + +A harness that only built features would relearn the same lessons forever. This one +remembers. [Long-term memory](./concepts/long-term-memory.md) — the Expert (lazy, +pulled on demand), `AGENTS.md` (eager, a map into the Expert), and lints (the memory +an agent cannot ship past) — is updated on every merge through a single, auditable +write path. + +That is the start of [continuous improvement](./concepts/continuous-improvement.md), +the idea at the center of the whole system: **you operate on the system that +produces features, not on the features themselves.** Fix a piece of code and you +ship one feature. Fix a context gap and every future feature benefits. You do both, +but context-gap fixes are the main thing, because they compound — and the +ready-to-merge ratio is the metric you drive up. + +## Your job: the human loop + +Strip away the typing and what is left is not less work — it is higher-leverage +work. [The human loop](./concepts/the-human-loop.md) is the part a harness cannot +do: **understand** the problem (`/wiki-init`), express **intent** with a real +definition of done (`/intent`), and **evaluate** what comes back (`/evaluate-pr`, +`/evaluate-sessions`). When you evaluate, you don't just approve work — you improve +the thing that produced it. + +Put it together and your project stops being a codebase you type into and becomes a +harness you tune. A codebase you type into is a constant cost. A harness you tune is +an appreciating asset — each feature leaves it a little more capable of building the +next one. + +## Keep reading + +- Jump into any [core concept](./README.md#core-concepts). +- Follow a [how-to guide](./README.md#how-to-guides) to do something specific. +- Read the [design invariants](./reference/invariants.md) for the proof the machine + is safe to leave running. diff --git a/docs/reference/cli.md b/docs/reference/cli.md new file mode 100644 index 0000000..f27673c --- /dev/null +++ b/docs/reference/cli.md @@ -0,0 +1,55 @@ +# Reference: the `context-specs` CLI + +`context-specs` is the deterministic half of the harness — the CLI that registers +environments, symlinks the canonical skills into them, and supervises the +dispatcher loops. It contains no LLM; it only schedules +[the dispatcher](../concepts/the-dispatcher.md) (`scripts/poll-and-dispatch.sh`). + +``` +Usage: context-specs [args] +``` + +Run `context-specs --help` for the built-in summary. + +## Setup + +| Command | Description | +|---|---| +| `init [name]` | Create (or adopt) a harness repo from the context-specs template. See [Create a harness](../how-to/create-a-harness.md). | +| `add [--name n]` | Register an environment repo: symlink skills, write `.gitignore` entries, add it to `environments.toml`. Then run `/env-init` inside it. See [Add an environment](../how-to/add-an-environment.md). | +| `remove ` | Unregister an environment (leaves its files and state in place). | +| `link ` | (Re-)create the skill/agent symlinks in a repo or worktree. Idempotent; called automatically by `bootstrap-worktree.sh`. | + +## Run + +| Command | Description | +|---|---| +| `start [name\|--all]` | Start the background supervisor (build loop + memory loop). | +| `stop [name\|--all]` | Stop the supervisor. | +| `run [name] [--learn]` | One foreground tick, drained to idle. No daemon. `--learn` runs the memory loop instead of the build loop. | +| `status [--fetch]` | One-shot table: every environment's features and phases. `--fetch` updates refs first. Applies the dispatcher's liveness gate (no merged/closed features). | +| `logs [-f] [--learn\|--supervisor]` | Show (or follow) an environment's logs. | +| `doctor` | Check the harness, the registry, and every environment. | + +See [Run the harness](../how-to/run-the-harness.md) for usage. + +## The scheduling protocol: exit codes + +The CLI schedules the dispatcher and reacts to its exit code — that is the entire +protocol: + +| Exit code | Meaning | Supervisor reaction | +|---|---|---| +| `0` | Idle — no work advanced | Sleep the interval (default 5 min), then tick again | +| `10` | Work advanced | Re-invoke immediately, until the environment is idle | +| non-zero (other) | Error | Back off exponentially | + +A STUCK feature reports idle, so a stuck environment never hot-loops. + +## Related + +- [The dispatcher](../concepts/the-dispatcher.md) — the deterministic engine this + CLI drives. +- [Reference: state and branches](./state-and-branches.md) — where the CLI's state + lives. +- [Reference: skills](./skills.md) — the probabilistic half the CLI hands off to. diff --git a/docs/invariants.md b/docs/reference/invariants.md similarity index 97% rename from docs/invariants.md rename to docs/reference/invariants.md index c9d2e1f..409e650 100644 --- a/docs/invariants.md +++ b/docs/reference/invariants.md @@ -1,7 +1,7 @@ # Design invariants -This is the reference companion to the [documentation story](./README.md) — -specifically [Chapter 3, The agent harness](./3-the-agent-harness.md), which +This is the reference companion to the [documentation overview](../overview.md) — +specifically [The dispatcher](../concepts/the-dispatcher.md), which gives you the intuition for why the harness is safe to leave running. This document gives you the *proof*: it enumerates the properties the harness holds no matter what crashes, races, or restarts. @@ -373,6 +373,6 @@ Each walkthrough names the failure, traces what happens tick by tick, and points ## See also -- [The documentation story](./README.md) — the narrative these properties underpin, starting from context engineering. -- [Chapter 3 — The agent harness](./3-the-agent-harness.md) — the intuition for why the harness is safe; this document is its proof. -- [`scripts/poll-and-dispatch.sh`](../scripts/poll-and-dispatch.sh) — the dispatcher: the canonical realization of these invariants in code. +- [Documentation overview](../overview.md) — the narrative these properties underpin, starting from context engineering. +- [The dispatcher](../concepts/the-dispatcher.md) — the intuition for why the harness is safe; this document is its proof. +- [`scripts/poll-and-dispatch.sh`](../../scripts/poll-and-dispatch.sh) — the dispatcher: the canonical realization of these invariants in code. diff --git a/docs/reference/skills.md b/docs/reference/skills.md new file mode 100644 index 0000000..3d117f5 --- /dev/null +++ b/docs/reference/skills.md @@ -0,0 +1,59 @@ +# Reference: the pieces + +Context Specs is a deterministic CLI and dispatcher plus a set of Agent Skills. This +is the catalog. The CLI and dispatchers are the harness's deterministic half; the +skills are its probabilistic half. + +## Deterministic half + +| Where | Piece | Does | +|---|---|---| +| **CLI** (`bin/context-specs`) | `init` / `add` / `link` / `remove` | Create the harness repo; register environments; symlink skills | +| | `start` / `stop` / `run` | Supervise the loops (drain-on-advance) / one foreground pass | +| | `status` / `logs` / `doctor` | Observe every environment; check the wiring | +| **Dispatchers** (`scripts/`) | `poll-and-dispatch.sh` | The build loop: PRD → PR, one deterministic step per tick | +| | `learn-dispatch.sh` | The memory loop: merged diff → `learn/` PR | + +See [Reference: the CLI](./cli.md) for full command detail. + +## Probabilistic half — Agent Skills + +### SDD skills (`skills/sdd/`) — short-term memory + +| Skill | Does | +|---|---| +| [`/spec-planning`](../../skills/sdd/spec-planning/SKILL.md) | PRD → mainspec + temporal slices | +| [`/spec-validate`](../../skills/sdd/spec-validate/SKILL.md) | Multi-agent consensus review of the plan | +| [`/implement-mainspec`](../../skills/sdd/implement-mainspec/SKILL.md) | Orchestrate slices in dependency order | +| [`/implement-slice`](../../skills/sdd/implement-slice/SKILL.md) | Implement one slice: write, unit-test, Reflect | + +See [Spec-Driven Development](../concepts/spec-driven-development.md). + +### Harness skills (`skills/harness/`) + +| Skill | Does | +|---|---| +| [`/env-init`](../../skills/harness/env-init/SKILL.md) | Guided setup of a project as an environment (the Software 3.0 half) | +| [`/fix-local-checks`](../../skills/harness/fix-local-checks/SKILL.md) | Honest fixes for a failing pre-PR gate | +| [`/address-feedback`](../../skills/harness/address-feedback/SKILL.md) | Triage and answer reviewer findings | +| [`/learn`](../../skills/harness/learn/SKILL.md) | Post-merge long-term memory update | + +See [Long-term memory](../concepts/long-term-memory.md). + +### Human-loop skills (`skills/human-loop/`) + +| Skill | Does | +|---|---| +| [`/wiki-init`](../../skills/human-loop/wiki-init/SKILL.md) | Stand up a Karpathy LLM-wiki (Understanding) | +| [`/intent`](../../skills/human-loop/intent/SKILL.md) | Idea → PRD + runnable definition of done (project-owned) | +| [`/evaluate-pr`](../../skills/human-loop/evaluate-pr/SKILL.md) | Evaluate the change; build understanding | +| [`/evaluate-sessions`](../../skills/human-loop/evaluate-sessions/SKILL.md) | Evaluate the build trail; capture evals | + +See [The human loop](../concepts/the-human-loop.md). + +## Project-owned vs. harness-owned + +Most skills are symlinked from the harness repo into each environment (gitignored). +Two are deliberately project-owned — committed to the environment and tuned per +project: **`/intent`** and the **Expert**. See +[the two-tier architecture](../concepts/two-tier-architecture.md#the-two-developer-owned-levers). diff --git a/docs/reference/state-and-branches.md b/docs/reference/state-and-branches.md new file mode 100644 index 0000000..8d50c49 --- /dev/null +++ b/docs/reference/state-and-branches.md @@ -0,0 +1,70 @@ +# Reference: state and branches + +The harness keeps **no hidden state**. Everything it knows is observable from two +places: the branches in git and the files on disk. This page documents both. For +why this design makes the harness safe to leave running, see +[the dispatcher](../concepts/the-dispatcher.md) and the +[design invariants](./invariants.md). + +## The branch namespace is the work queue + +There is no separate database of "what work exists." The branches *are* the +registry: + +| Branch | Role | +|---|---| +| `prd//` | `/intent` output — the waiting queue. An atomic rename to `feature/` is how the harness claims it. | +| `feature/` | The active implementation lane. | +| `main` | Humans merge here. Never pushed to directly. | +| `learn/` | Auto-generated memory update from the memory loop. | + +Claiming a feature is a single atomic git operation — renaming +`prd//` to `feature/`. If two harnesses ever race for the +same work, whichever pushes the rename first wins and the other moves on. No lock +service, no coordination daemon — git refs are the lock. + +By default each developer's harness watches only their own `prd//*` queue, +so your harness is your personal assistant, not a shared teammate. + +## Worktrees + +The harness never touches your checkout. It does all its work in **sibling +worktrees** it creates and tears down itself, named `-harness-`. Your +uncommitted work is structurally out of its reach. The worktree is set up by +`scripts/bootstrap-worktree.sh`, which also re-links the skill symlinks (they are +wiped with the worktree on each tick). + +## On-disk layout + +Following the [two-tier architecture](../concepts/two-tier-architecture.md): + +### Harness repo (tier 1) + +``` +bin/context-specs the CLI +scripts/ the dispatchers (poll-and-dispatch.sh, learn-dispatch.sh, harness-lib.sh) +skills/ canonical skills (symlinked into environments) +state// per-environment runtime state (logs, locks, supervisor bookkeeping) +environments.toml the registry of registered environments +``` + +### Environment repo (tier 2) + +``` +AGENTS.md the eager contract (a map into the Expert) +.claude/skills/intent/ project-owned /intent (committed) +.claude/skills/expert/ long-term memory (committed) +.claude/skills/* canonical skills (symlinked, gitignored) +scripts/ bootstrap-worktree.sh, local-checks.sh +prds// prd.md + run-prd-test.sh +specs// mainspec.md + slices/ (short-term memory) +evals/ captured regression checks over skills and context +.harness/env this environment's dials +``` + +## Related + +- [The dispatcher](../concepts/the-dispatcher.md) — reads this state fresh each + tick. +- [Design invariants](./invariants.md) — the properties this layout guarantees. +- [Reference: the CLI](./cli.md) — the commands that operate on this state.