compounding-loop 0.2.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -3
- package/dist/cli/claim.js +84 -0
- package/dist/cli/claim.js.map +1 -0
- package/dist/cli/draft.js +69 -0
- package/dist/cli/draft.js.map +1 -0
- package/dist/cli/index.js +284 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/laneRound.js +96 -0
- package/dist/cli/laneRound.js.map +1 -0
- package/dist/cli/laneStatus.js +3 -1
- package/dist/cli/laneStatus.js.map +1 -1
- package/dist/cli/lanesInit.js +8 -2
- package/dist/cli/lanesInit.js.map +1 -1
- package/dist/cli/lock.js +22 -2
- package/dist/cli/lock.js.map +1 -1
- package/dist/cli/loops.js +7 -0
- package/dist/cli/loops.js.map +1 -1
- package/dist/cli/next.js +18 -0
- package/dist/cli/next.js.map +1 -0
- package/dist/cli/pace.js +41 -0
- package/dist/cli/pace.js.map +1 -0
- package/dist/cli/pause.js +81 -0
- package/dist/cli/pause.js.map +1 -0
- package/dist/cli/run.js +18 -6
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/runs.js +118 -0
- package/dist/cli/runs.js.map +1 -0
- package/dist/cli/schedule.js +177 -0
- package/dist/cli/schedule.js.map +1 -0
- package/dist/cli/shipCheck.js +59 -0
- package/dist/cli/shipCheck.js.map +1 -0
- package/dist/core/brief.js +35 -12
- package/dist/core/brief.js.map +1 -1
- package/dist/core/draftBrief.js +68 -0
- package/dist/core/draftBrief.js.map +1 -0
- package/dist/core/laneRound.js +63 -0
- package/dist/core/laneRound.js.map +1 -0
- package/dist/core/lanes.js +15 -2
- package/dist/core/lanes.js.map +1 -1
- package/dist/core/lanesInit.js +19 -0
- package/dist/core/lanesInit.js.map +1 -1
- package/dist/core/next.js +34 -0
- package/dist/core/next.js.map +1 -0
- package/dist/core/parse/changelog.js +41 -0
- package/dist/core/parse/changelog.js.map +1 -0
- package/dist/core/parse/claim.js +24 -0
- package/dist/core/parse/claim.js.map +1 -0
- package/dist/core/parse/controlRoom.js +38 -0
- package/dist/core/parse/controlRoom.js.map +1 -0
- package/dist/core/parse/index.js +17 -0
- package/dist/core/parse/index.js.map +1 -0
- package/dist/core/parse/markers.js +20 -0
- package/dist/core/parse/markers.js.map +1 -0
- package/dist/core/parse/outcomes.js +51 -0
- package/dist/core/parse/outcomes.js.map +1 -0
- package/dist/core/parse/paused.js +26 -0
- package/dist/core/parse/paused.js.map +1 -0
- package/dist/core/parse/policy.js +56 -0
- package/dist/core/parse/policy.js.map +1 -0
- package/dist/core/parse/runs.js +132 -0
- package/dist/core/parse/runs.js.map +1 -0
- package/dist/core/parse/schedule.js +101 -0
- package/dist/core/parse/schedule.js.map +1 -0
- package/dist/core/parse/steer.js +68 -0
- package/dist/core/parse/steer.js.map +1 -0
- package/dist/core/parse/task.js +96 -0
- package/dist/core/parse/task.js.map +1 -0
- package/dist/core/repo.js +18 -8
- package/dist/core/repo.js.map +1 -1
- package/dist/core/runPrompt.js +8 -2
- package/dist/core/runPrompt.js.map +1 -1
- package/dist/core/shipCheck.js +45 -0
- package/dist/core/shipCheck.js.map +1 -0
- package/dist/core/table.js +3 -1
- package/dist/core/table.js.map +1 -1
- package/dist/server/actionBody.js +54 -0
- package/dist/server/actionBody.js.map +1 -0
- package/dist/server/checkLabels.js +32 -0
- package/dist/server/checkLabels.js.map +1 -0
- package/dist/server/claude.js +18 -0
- package/dist/server/claude.js.map +1 -0
- package/dist/server/controls.js +99 -0
- package/dist/server/controls.js.map +1 -0
- package/dist/server/data.js +9 -3
- package/dist/server/data.js.map +1 -1
- package/dist/server/draftInputs.js +33 -0
- package/dist/server/draftInputs.js.map +1 -0
- package/dist/server/health.js +9 -30
- package/dist/server/health.js.map +1 -1
- package/dist/server/index.js +77 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/laneChecks.js +25 -0
- package/dist/server/laneChecks.js.map +1 -0
- package/dist/server/laneSchedule.js +15 -0
- package/dist/server/laneSchedule.js.map +1 -0
- package/dist/server/live/build.js +178 -0
- package/dist/server/live/build.js.map +1 -0
- package/dist/server/live/github.js +54 -0
- package/dist/server/live/github.js.map +1 -0
- package/dist/server/live/index.js +11 -0
- package/dist/server/live/index.js.map +1 -0
- package/dist/server/live/merge.js +16 -0
- package/dist/server/live/merge.js.map +1 -0
- package/dist/server/live/urls.js +61 -0
- package/dist/server/live/urls.js.map +1 -0
- package/dist/server/loops.js +263 -41
- package/dist/server/loops.js.map +1 -1
- package/dist/server/paceNote.js +13 -0
- package/dist/server/paceNote.js.map +1 -0
- package/dist/server/roundState.js +51 -0
- package/dist/server/roundState.js.map +1 -0
- package/dist/server/runs.js +144 -0
- package/dist/server/runs.js.map +1 -0
- package/dist/server/shipped.js +35 -0
- package/dist/server/shipped.js.map +1 -0
- package/dist/server/static-export.js +22 -1
- package/dist/server/static-export.js.map +1 -1
- package/dist/server/taskBullets.js +33 -0
- package/dist/server/taskBullets.js.map +1 -0
- package/dist/server/this-repo.json +2818 -106
- package/dist/web/assets/index-BozIcdeb.js +88 -0
- package/dist/web/assets/index-Te_olhNA.css +2 -0
- package/dist/web/index.html +2 -2
- package/method/COMPOUNDING_LOOP.md +26 -0
- package/method/retro.md +7 -0
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/commands/loop-lanes.md +11 -0
- package/plugin/commands/loop-next.md +11 -0
- package/plugin/commands/loop-pause.md +10 -0
- package/runners/github-actions/lanes.yml +55 -2
- package/runners/local/README.md +3 -1
- package/runners/local/compounding-loop.service +20 -0
- package/runners/local/compounding-loop.timer +11 -0
- package/runners/routine/README.md +5 -1
- package/runners/routine/control-room-prompt.md +4 -14
- package/runners/routine/lane-prompt.md +4 -10
- package/runners/routine/prompt.md +2 -2
- package/templates/lanes/README.md +5 -1
- package/templates/lanes/claude-section.md +5 -1
- package/templates/lanes/control-run.md +37 -0
- package/templates/lanes/lane-run.md +33 -0
- package/templates/lanes/schedule.json +4 -0
- package/templates/lanes/steer.md +3 -0
- package/templates/lanes/task.md +1 -1
- package/templates/static-site/.ai/loop-prompt.md +1 -1
- package/templates/static-site/CLAUDE.md +2 -0
- package/dist/web/assets/index-B16QCSnY.css +0 -2
- package/dist/web/assets/index-CS82DKbF.js +0 -49
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:"Inter Variable", system-ui, sans-serif;--font-mono:"JetBrains Mono Variable", ui-monospace, monospace;--spacing:.25rem;--container-xl:36rem;--container-2xl:42rem;--container-3xl:48rem;--container-6xl:72rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.top-0{top:0}.top-1{top:var(--spacing)}.top-24{top:calc(var(--spacing) * 24)}.right-1{right:var(--spacing)}.right-4{right:calc(var(--spacing) * 4)}.-bottom-4{bottom:calc(var(--spacing) * -4)}.bottom-4{bottom:calc(var(--spacing) * 4)}.left-1\/2{left:50%}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.order-1{order:1}.order-2{order:2}.order-3{order:3}.-mx-4{margin-inline:calc(var(--spacing) * -4)}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-\[2px\]{margin-top:2px}.mt-\[3px\]{margin-top:3px}.mr-2{margin-right:calc(var(--spacing) * 2)}.mr-3{margin-right:calc(var(--spacing) * 3)}.mr-4{margin-right:calc(var(--spacing) * 4)}.-mb-2{margin-bottom:calc(var(--spacing) * -2)}.-mb-4{margin-bottom:calc(var(--spacing) * -4)}.mb-1{margin-bottom:var(--spacing)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-5{margin-bottom:calc(var(--spacing) * 5)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.ml-1\.5{margin-left:calc(var(--spacing) * 1.5)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.size-2{width:calc(var(--spacing) * 2);height:calc(var(--spacing) * 2)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-11{width:calc(var(--spacing) * 11);height:calc(var(--spacing) * 11)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-5{height:calc(var(--spacing) * 5)}.h-20{height:calc(var(--spacing) * 20)}.h-24{height:calc(var(--spacing) * 24)}.h-28{height:calc(var(--spacing) * 28)}.h-full{height:100%}.max-h-32{max-height:calc(var(--spacing) * 32)}.max-h-40{max-height:calc(var(--spacing) * 40)}.max-h-48{max-height:calc(var(--spacing) * 48)}.max-h-72{max-height:calc(var(--spacing) * 72)}.min-h-5{min-height:calc(var(--spacing) * 5)}.min-h-11{min-height:calc(var(--spacing) * 11)}.min-h-\[44px\]{min-height:44px}.w-2{width:calc(var(--spacing) * 2)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-48{width:calc(var(--spacing) * 48)}.w-\[calc\(100\%\+2rem\)\]{width:calc(100% + 2rem)}.w-\[min\(32rem\,calc\(100vw-2rem\)\)\]{width:min(32rem,100vw - 2rem)}.w-\[min\(36rem\,calc\(100vw-2rem\)\)\]{width:min(36rem,100vw - 2rem)}.w-\[min\(44rem\,calc\(100vw-2rem\)\)\]{width:min(44rem,100vw - 2rem)}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-3xl{max-width:var(--container-3xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-\[calc\(100vw-2rem\)\]{max-width:calc(100vw - 2rem)}.max-w-full{max-width:100%}.max-w-xl{max-width:var(--container-xl)}.min-w-0{min-width:0}.flex-1{flex:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.basis-64{flex-basis:calc(var(--spacing) * 64)}.basis-full{flex-basis:100%}.border-separate{border-collapse:separate}.\[border-spacing\:2px\]{border-spacing:2px}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.animate-pulse{animation:var(--animate-pulse)}.cursor-pointer{cursor:pointer}.list-disc{list-style-type:disc}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.grid-cols-\[max-content_1fr\]{grid-template-columns:max-content 1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.content-center{align-content:center}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-x-6{column-gap:calc(var(--spacing) * 6)}.gap-y-0\.5{row-gap:calc(var(--spacing) * .5)}.gap-y-1{row-gap:var(--spacing)}.gap-y-2{row-gap:calc(var(--spacing) * 2)}.self-center{align-self:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:2147483647px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-r{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l-\[3px\]{border-left-style:var(--tw-border-style);border-left-width:3px}.p-0{padding:0}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.px-1{padding-inline:var(--spacing)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-6{padding-block:calc(var(--spacing) * 6)}.pr-1{padding-right:var(--spacing)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pr-12{padding-right:calc(var(--spacing) * 12)}.pb-1{padding-bottom:var(--spacing)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-5{padding-left:calc(var(--spacing) * 5)}.pl-6{padding-left:calc(var(--spacing) * 6)}.text-center{text-align:center}.text-left{text-align:left}.align-bottom{vertical-align:bottom}.font-mono{font-family:var(--font-mono)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-\[10px\]{font-size:10px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[20px\]{font-size:20px}.text-\[28px\]{font-size:28px}.leading-7{--tw-leading:calc(var(--spacing) * 7);line-height:calc(var(--spacing) * 7)}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.\[overflow-wrap\:anywhere\]{overflow-wrap:anywhere}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.lowercase{text-transform:lowercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.underline{text-decoration-line:underline}.underline-offset-2{text-underline-offset:2px}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.outline-none{--tw-outline-style:none;outline-style:none}.open\:mb-0:is([open],:popover-open,:open){margin-bottom:0}@media (hover:hover){.hover\:underline:hover{text-decoration-line:underline}}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:outline-offset-1:focus-visible{outline-offset:1px}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}.has-\[\:checked\]\:border-\[var\(--accent\)\]:has(:checked){border-color:var(--accent)}.aria-pressed\:font-semibold[aria-pressed=true]{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.has-\[\:checked\]\:font-semibold:has(:checked){--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.aria-pressed\:underline[aria-pressed=true]{text-decoration-line:underline}.aria-selected\:border-b-2[aria-selected=true]{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.aria-selected\:font-semibold[aria-selected=true]{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.aria-\[current\=page\]\:bg-\[var\(--border\)\][aria-current=page]{background-color:var(--border)}.aria-\[current\=step\]\:font-semibold[aria-current=step]{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.data-\[selected\=true\]\:border-\[var\(--accent\)\][data-selected=true]{border-color:var(--accent)}.data-\[selected\=true\]\:bg-\[var\(--border\)\][data-selected=true]{background-color:var(--border)}@media not all and (width>=48rem){.max-md\:hidden{display:none}.max-md\:h-56{height:calc(var(--spacing) * 56)}}@media (width>=40rem){.sm\:not-sr-only{clip-path:none;white-space:normal;width:auto;height:auto;margin:0;padding:0;position:static;overflow:visible}.sm\:col-span-2{grid-column:span 2/span 2}.sm\:hidden{display:none}.sm\:table-cell{display:table-cell}.sm\:min-h-0{min-height:0}.sm\:min-h-8{min-height:calc(var(--spacing) * 8)}.sm\:w-auto{width:auto}.sm\:basis-0{flex-basis:0}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-\[10rem_1fr\]{grid-template-columns:10rem 1fr}.sm\:p-4{padding:calc(var(--spacing) * 4)}}@media (width>=48rem){.md\:order-2{order:2}.md\:order-3{order:3}.md\:mx-0{margin-inline:0}.md\:ml-0{margin-left:0}.md\:hidden{display:none}.md\:inline{display:inline}.md\:min-h-0{min-height:0}.md\:min-h-8{min-height:calc(var(--spacing) * 8)}.md\:min-h-9{min-height:calc(var(--spacing) * 9)}.md\:w-auto{width:auto}.md\:flex-1{flex:1}.md\:gap-x-6{column-gap:calc(var(--spacing) * 6)}.md\:overflow-visible{overflow:visible}.md\:p-5{padding:calc(var(--spacing) * 5)}.md\:px-0{padding-inline:0}.md\:py-3{padding-block:calc(var(--spacing) * 3)}.md\:pr-14{padding-right:calc(var(--spacing) * 14)}}@media (width>=64rem){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2)format("woff2-variations");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-cyrillic-wght-normal-DqGufNeO.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-greek-ext-wght-normal-DlzME5K_.woff2)format("woff2-variations");unicode-range:U+1F??}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-greek-wght-normal-CkhJZR-_.woff2)format("woff2-variations");unicode-range:U+370-377,U+37A-37F,U+384-38A,U+38C,U+38E-3A1,U+3A3-3FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-vietnamese-wght-normal-CBcvBZtf.woff2)format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-latin-ext-wght-normal-DO1Apj_S.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-latin-wght-normal-Dx4kXJAl.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(data:font/woff2;base64,d09GMgABAAAAAAfsABQAAAAAEAwAAAeCAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhwbHhwoP0hWQVJbBmA/U1RBVIFiJyYAdC9qEQgKhGSEAAsgADCGCAE2AiQDOgQgBYlMB4EUDAcbLQ4onoexrSC/2ZyLAa8p8VHB8/x3Vue+V0hVJalMJg2nx/TCrQXxBeqLjQG7FyM1WEa/X1tEXN7cFz9EJEMmMUz3RihWSSKeQCbcIou0izz/C8v+fq3VfajEa9gDD11CImXS7qL/RJFVzC1qiB6KmKeD6TZdQ6IRGv78dL6uSVVCfgni5mzu7kcgQBgAEAQTQRCoL++STTYybkJxNfQxAAIAGu8OdEB9teW2jh4BpgDqFjAeSEByW3zFP0CBBgNMsMCGEDjgggdhiEAUAeIIED7ABTDUEnkIE9Q9ahFgKttcVhApo4ACB4qobHaccgDfEjFO6aaWUhjMLt2SyIvHKoDqoA4CSUwEIYQCEjhAO9R1G6keDeDZGjNo+AhxOjCEGTr1WeIF3kYBiLAOKvkJSMiKX0VdAyQt3SDJClCkxJCHkCzfqyVTriJZLcolS32JZHUekq2TYNkYtCtjYHMQXSxGjXDz2t/yLWXzDzxz+o3zFwDEaN23F+13pyMdQAEaSKAR9vcGq4A4MTSKCElGW+M7UcY7xqkggITb28ZJhlqc9q2twYKTt0NjixBgYvO9BIihEBLYuOFXQzfIQ7dXGUEEEgFDooBfAzqiQbpJrhiWSuKJCRFKYbHCyJKI2G5GiZbNAvgAu5pc3vwx4G+g3aDkhklABiSz0BICXrYghtYhx/cdJ+44rY2oZ0aMNRFz3VZjb6W33F3gzltqtOCV8tTHSpOeXuItfvr5lCdfzFpqtEitvqdcdGGFd28ZqqC0tPbeChGXgrIlnhSWu/eUso4uKWFLugyDzQJhflY4659+WjQ++6x72WUMv9G8mw6QJl7BVxX5fe/kpUsOvnZwee9uQ0cGXYd0o89XB2748sDSnt8d2VphdOTTgceDVvOds0v9P/s7HPq15aGun/6Vllb56f1dl0t1LejqrNkpdRZsG8TOnM5vkBG5oiVyVGnS8LHps5cfNWJs6qKPfaNSxiQNBUm3cKNWROr0GSur7Za31k1vieq7LH11VF+jXdRIasRKflc7jkobm1Z9te1IyZA0pDkhLR98+H37Zf1c/8at+dB7x+7GfVyTfJMPiYztsnl59Y5l4j+0n1RXlpHnF3Tq7HecmNF/CJodEMAikruxiyJaGLvHOdAfoA+oDvpjBm2b91cHGRZMU9n25xEU0A8fgEEAdKI3Q1iDtc034sug5YVMkE2jsE+BIkwSoQ3gxXMqz9tELp48bd0cFKOKS7xYjEuXBnZP5ia7DyiO/X/YI+PQSbt2uSdqAkWL9nQbV1XB94/+uPfdZz8dnXYFBYrcTl2SIR/ybxJNJPz/Gupb0JaZeens2ekC7EKr8t+Ls/P5VJPYJdHKyqfg2nqU6bhlidzcddQV/7MmecTzJ5VPcKXkNKSEogHjYFx6QZ7rQ+FSe8njaiNuOnXS8H2ScQ619c2mC3VTtauL0rRbXd/CkSOP37FY9Zkjz8+GibYUMOEWF+RdrFS8Ecv1SHOpPUPZGEIpjPvFyU5cXKjd6OXqorTqy9GwRd++HVufPGnVsW+aO3vggKZ18jR9sXaTC1PWTEsVUaK0FkNySbTQDqlm2PfDjZcu4aalnSLKjnOoYQ0nUlqqXcGpPu/4VgV/xU2pAqW4BW3qzhQ8/hFKhV2qE3+BKAtDqBXjfgnVdH4y0wg5tbVNRenNdTWOrenWLcupQdmsbq5b+18piTe/xRdp1xbILxNPJGInm2z6hoB21Lal0i+ePTtd7B45+3XhFJ329evskXm7qurUVREotqSluSo/L29d3qDhI4YOQqWhI4YNvBNfsMHeXKemXrxQfKeuPOGRVayA3JtkJKEgbPp+dXUDluddutRYLFoXGXWX6N3WFaGLbQtRSitVYNacTNSdy7AaG/HSaUEANcBoGXNdcZvZsOqQ1icBDv21/gzAoYPHH/WDW0qNR3QTYKEAEHig6o13NXbND06CQPlRtYjGNnSktRc09k1mAMDvAlDKfQjgy6fssInlfzmNAjKkDxoxHOBLdVRAIVt9j4qo+hA1w9T1aNBNTUOTTNUHLbqokE+UAfJXCIGw/IxCSL5GRUJeR40rL/UxTm4Q08H6MbCs70ObuNyIIXrINHQYInF06UUlevTjbQzTh5upiDMzMMogUtEnjPs/Y7jAHCJeB0GBHh04tC6FiB6ZFB1oArUSIoFoqhzCeAN6lHwm0T4C3VVPWvjpSMXReuWesMEcoqrmgtNBGd2noWeV0hNAz9rFeShNJxHGsPa3HXeKTk8b55hahySYHaYKKFFLpCfN8rsoaJn01CR04Gkc+5k7KVTCmClX8Q10HCrUEkVlSX+XO33oQR9609tJ516H497WSobWs5Up6TLaS10/dessIskgJSLiDlWvHVUywpkQ7hdPZqGyiEF0uVQerVcPamT1A3eKXdyI1vG9OoflrSXihZ1qqGE3nhmAgiIbRCQgPLEPtOM3UQwTLYaYYomNlpA44opnjV6jkD6id80OOrzf6BzmMD6eEa1zKyeYG1fzfEf16V6jw9XYOaar1/b2kP/IYX8oR2mcFvv2GtBV3JXgd437AQAA)format("woff2-variations");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(./jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(./jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2)format("woff2-variations");unicode-range:U+370-377,U+37A-37F,U+384-38A,U+38C,U+38E-3A1,U+3A3-3FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(./jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2)format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(./jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(./jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}:root{--bg:#0b0d10;--surface:#13161b;--surface-2:#181b21;--border:#232831;--text:#e6e8eb;--muted:#8b93a1;--accent:#8b7cff;--building:#4c8dff;--blocked:#f5a524;--done:#3ddc97;--failing:#f04d4d;--lane-core:#56b4e9;--lane-kit:#f0a030;--lane-server:#2fc79a;--lane-web:#e08bbe;--lane-docs:#e5d44a;--lane-other:var(--muted);--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}@media (prefers-color-scheme:light){:root:not([data-theme=dark]){--bg:#fafafa;--surface:#fff;--surface-2:#f3f4f6;--border:#e4e6ea;--text:#111318;--muted:#5b6370;--accent:#6c5ce7;--building:#2563eb;--blocked:#b45309;--done:#15803d;--failing:#dc2626;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}}:root[data-theme=light]{--bg:#fafafa;--surface:#fff;--surface-2:#f3f4f6;--border:#e4e6ea;--text:#111318;--muted:#5b6370;--accent:#6c5ce7;--building:#2563eb;--blocked:#b45309;--done:#15803d;--failing:#dc2626;--lane-core:#0072b2;--lane-kit:#b84a00;--lane-server:#007a5a;--lane-web:#a8467f;--lane-docs:#8a6d00;--lane-other:var(--muted);--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}body{background:var(--bg);color:var(--text);font-family:var(--font-sans);font-size:14px}a,button,input,[role=option]{outline-offset:2px}:focus-visible{outline:2px solid var(--accent)}@media (prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition-duration:.01ms!important;animation-duration:.01ms!important}}dialog:modal{max-height:calc(100dvh - 2rem);margin:auto;overflow-y:auto}dialog::backdrop{background:#0000008c}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@keyframes pulse{50%{opacity:.5}}
|
package/dist/web/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="./favicon.svg" />
|
|
7
7
|
<title>Compounding Loop</title>
|
|
8
|
-
<script type="module" crossorigin src="./assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-BozIcdeb.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="./assets/index-Te_olhNA.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
|
@@ -408,6 +408,32 @@ A lane is one scheduled run that owns one part of the codebase. Several lanes pu
|
|
|
408
408
|
3. Never force-push. A lane's history is the other lanes' history too.
|
|
409
409
|
4. Each lane has its own task file, run counter, `DONE.md` and `BLOCKED.md`. Only the control room writes the root `DONE.md`.
|
|
410
410
|
|
|
411
|
+
**Working with teammates.** A teammate joins by cloning the repository; everything their own Claude Code needs is in the repo, and nothing private is ever handed over (no keys, no chat logs, no local paths). `.ai/` is the shared memory: task files say what is open, outboxes say what is waiting, `.ai/index.md` holds what was learned.
|
|
412
|
+
|
|
413
|
+
1. Clone the repo and run the install command from `CLAUDE.md`.
|
|
414
|
+
2. `loop next` lists the open units across all lanes with their claims and recommends one nobody holds.
|
|
415
|
+
3. `loop claim <lane> --as <name>` writes `.ai/lanes/<lane>/claim` (one line, `name · expires <UTC time>`), commits it with the trailer `Lane: <lane>` and pushes. From then on the scheduled runs of that lane reply "Nothing to do" until the claim expires, so you and a routine never edit the same lane at once.
|
|
416
|
+
4. `loop run --lane <lane>` (or Claude Code with the lane prompt) does the work and pushes to `main` like any run.
|
|
417
|
+
5. `loop release <lane>` removes the claim. If you forget, it expires on its own (90 minutes by default), and an expired claim counts as none.
|
|
418
|
+
|
|
419
|
+
A claim protects a lane, not a file: ownership of paths still decides what a lane may edit. Do not claim a lane to keep it idle; claim it while you are working in it.
|
|
420
|
+
|
|
421
|
+
**Controlling a loop.** Everything an owner does between runs is a change to a file in the repo, so a dashboard, a script or a person at a terminal can do it the same way. The scheduled runs stay enabled; the repo decides whether they work.
|
|
422
|
+
|
|
423
|
+
| Control | What it changes in the repo | Effect on the next scheduled run |
|
|
424
|
+
|---|---|---|
|
|
425
|
+
| Pause (`loop pause [--reason]`) | adds `.ai/PAUSED` (one line: who, when, optional reason), commit trailer `Lane: control` | every lane and the control room replies "Paused" and stops |
|
|
426
|
+
| Resume (`loop resume`) | removes `.ai/PAUSED` | runs work again |
|
|
427
|
+
| Next round (`loop next-round --brief <file>`) | puts the brief at the top of `IDEA.md`, archives root and lane `DONE.md` files as `done-vN.md`, resets each lane's task file, adds a control-room note | lanes start the new round at unit 1 |
|
|
428
|
+
| Release | a reviewed manual workflow on the default branch bumps nothing itself: it checks the ship list (root `DONE.md`, a changelog section, no existing tag), publishes with the registry's trusted publishing (no token anywhere) and tags | none; lanes see the tag and the changelog |
|
|
429
|
+
|
|
430
|
+
Every run, successful or not, appends one line to `.ai/lanes/<lane>/runs.jsonl` (`loop runs log`); `loop runs` compares those lines and the commits with each lane's scheduled slots, so a slot with neither is shown as "no run recorded", which on a subscription plan usually means the usage limit. A run that cannot pull because its clone started from an old copy fetches `origin main`, works on a branch from it and pushes with `git push origin HEAD:main`; origin `main` is never reset or force-pushed.
|
|
431
|
+
|
|
432
|
+
**Thin prompts, schedule, steering.** The routine prompt should be a few lines: name the lane, do the pull (with the stale-clone recovery) and say "follow `.ai/lane-run.md`" (the control room: `.ai/control-run.md`). The procedure lives in the repo, so changing how every lane runs is a commit, not an edit in five routine settings. `loop init --lanes` writes both files from the kit templates. Two more files let you leave the loop on around the clock:
|
|
433
|
+
|
|
434
|
+
- `.ai/schedule.json` (`{"version":1,"lanes":{"<lane>":{"notBefore":ISO|null,"sleeping":bool,"paused":bool,"reason":string|null}}}`): the first thing a run checks, before any install. A lane that is paused, sleeping or before its `notBefore` replies "Not due" and stops in seconds. A missing file or entry means due. A lane that shipped nothing backs itself off (1 idle run: 3 h, 2 in a row: 6 h, 3 or more: sleeping); the control room wakes it when it has a steer entry, a message or a new round. Only the owner pauses a lane.
|
|
435
|
+
- `.ai/lanes/<lane>/steer.md`: notes from the owner, newest first, each a heading `## YYYY-MM-DD HH:MM UTC · <author> · next-run|standing`. `next-run` entries come before the lane's own unit order, `standing` entries apply until removed. The lane acknowledges each with one line under it (`→ done in run N` or `→ not done: <why>`); that is the only edit it makes to the file.
|
|
436
|
+
|
|
411
437
|
**Failure modes seen when this repo was built by five lanes**
|
|
412
438
|
|
|
413
439
|
- **Stale sandbox clones.** A cloud run can start from an old clone and report that someone force-pushed or that a file vanished. Check `git log` on a fresh pull before believing a run's account of history.
|
package/method/retro.md
CHANGED
|
@@ -8,3 +8,10 @@ Run it when the checks pass, before deleting `.ai/task.md`. About two minutes.
|
|
|
8
8
|
4. Flag entries this task showed to be wrong or stale. Never delete a CONFIRMED entry without new evidence.
|
|
9
9
|
5. Add one line to `.ai/log.md`: date, task, checks result, runs used, what was learned.
|
|
10
10
|
6. Delete `.ai/task.md`.
|
|
11
|
+
|
|
12
|
+
## In a lane
|
|
13
|
+
|
|
14
|
+
- The task file is `.ai/lanes/<lane>/task.md`. Keep it for the record and set `Status:` instead of deleting it (the control room reads it).
|
|
15
|
+
- Write knowledge entries and the `.ai/index.md` line only for things that help any lane; put lane-only facts under Confirmed in your task file.
|
|
16
|
+
- Before writing your lane's `DONE.md`, read the other lanes' outboxes: if anyone waits on you, answer first.
|
|
17
|
+
- If the lesson is about another lane's files, tell them in your outbox. Do not edit their paths.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compounding-loop",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Run unattended, verified Claude Code build loops: set up a repo, hand off between windows, run retros and escape stuck loops.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": ["loop", "unattended", "verification", "handoff", "retro"]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Split this repository into parallel lanes, each owning its own folders, so scheduled runs never edit the same files
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Set up lanes in this repository.
|
|
6
|
+
|
|
7
|
+
1. Ask the user which parts of the code could be built independently (for example `core`, `web`, `docs`) and which folders each one owns. Keep it to two to five lanes.
|
|
8
|
+
2. Run `npx compounding-loop init --lanes <name1>,<name2>,... --dry-run` and show the user what it would write.
|
|
9
|
+
3. After a yes, run it again without `--dry-run`. It writes `.ai/lanes.json` and a task file, outbox and lane section per lane. Existing files are kept.
|
|
10
|
+
4. Open `.ai/lanes.json` and replace the placeholder `owns` globs (`<name>/**`) with the real folders.
|
|
11
|
+
5. From now on every commit ends with a `Lane: <lane>` trailer. `npx compounding-loop check-lanes` verifies ownership and can run in CI. To add a lane later: `npx compounding-loop lanes add <name> --owns "<glob>"`.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Pick the next open unit with a teammate in mind, claim its lane and start working
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Find work in this repository without colliding with a teammate or a scheduled run.
|
|
6
|
+
|
|
7
|
+
1. Run `npx compounding-loop next --json`. It lists the open units across all lanes with their claims and recommends one nobody holds. If it recommends nothing, say so and stop.
|
|
8
|
+
2. Show the user the recommended lane and unit in one line and wait for a yes, or for a different lane.
|
|
9
|
+
3. Claim it: `npx compounding-loop claim <lane> --as <name>` (the name defaults to `git config user.name`). This commits `.ai/lanes/<lane>/claim` with the trailer `Lane: <lane>` and pushes.
|
|
10
|
+
4. Read `.ai/lanes/<lane>/task.md` and work the unit as that lane: edit only the paths the lane owns, end every commit with `Lane: <lane>`.
|
|
11
|
+
5. When you stop, run `npx compounding-loop release <lane>`. An unreleased claim expires by itself.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Pause or resume every scheduled lane run and the control room, so routines can stay enabled
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Stop or restart the unattended runs of this repository without touching any scheduler.
|
|
6
|
+
|
|
7
|
+
1. Check the current state: `npx compounding-loop status`. If `.ai/PAUSED` exists it says who paused the loop and since when.
|
|
8
|
+
2. To pause, run `npx compounding-loop pause --reason "<why, one line>"`. It writes `.ai/PAUSED` and commits it with the trailer `Lane: control`. Every lane and the control room reply "Paused" and stop on their next run.
|
|
9
|
+
3. To resume, run `npx compounding-loop resume`. It removes `.ai/PAUSED` and commits that.
|
|
10
|
+
4. Tell the user in one line what changed and that the schedules themselves were not touched. If a push is refused, say so and leave the local commit in place.
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
# 3. The `verify` job runs `loop check-lanes`, which needs compounding-loop 0.2.0 or later.
|
|
10
10
|
# 4. Edit the `lane` and `cron` pairs in the matrix to match .ai/lanes.json, and keep the same
|
|
11
11
|
# cron strings in `on.schedule` (see runners/routine/README.md for staggering N lanes).
|
|
12
|
+
# 5. The `control` job (control room, every 3 hours) is optional. To drop it, delete its cron line,
|
|
13
|
+
# the `control` job, and `control` from `verify.needs`.
|
|
12
14
|
#
|
|
13
15
|
# How it runs: every cron line starts the whole matrix, and each job does real work only when
|
|
14
16
|
# the schedule that fired is its own (or when started by hand), so one lane runs per trigger.
|
|
@@ -19,6 +21,7 @@ on:
|
|
|
19
21
|
- cron: "7 * * * *"
|
|
20
22
|
- cron: "19 * * * *"
|
|
21
23
|
- cron: "31 * * * *"
|
|
24
|
+
- cron: "47 */3 * * *" # control room, every 3 hours (optional: delete this line and the `control` job)
|
|
22
25
|
workflow_dispatch: {}
|
|
23
26
|
|
|
24
27
|
# Workflow-level default: read only. The lane job raises it, because the lane pushes to main.
|
|
@@ -74,17 +77,67 @@ jobs:
|
|
|
74
77
|
# ("${{ matrix.lane }}" works for the lane). Short form shown:
|
|
75
78
|
prompt: |
|
|
76
79
|
You are one scheduled run of the ${{ matrix.lane }} lane of an unattended build loop.
|
|
77
|
-
Read CLAUDE.md and follow it exactly. Your task file is .ai/lanes/${{ matrix.lane }}/task.md.
|
|
80
|
+
Read CLAUDE.md and follow it exactly. Your task file is .ai/lanes/${{ matrix.lane }}/task.md. After the pull below, follow .ai/lane-run.md from step 1 with <lane> = ${{ matrix.lane }}: it has the cheap stop checks (a lane not due in .ai/schedule.json replies "Not due" and stops before the install), the steer step (.ai/lanes/${{ matrix.lane }}/steer.md) and the run log.
|
|
78
81
|
Every commit ends with the trailer line "Lane: ${{ matrix.lane }}". Push to main, never to a claude/ branch.
|
|
82
|
+
If .ai/PAUSED exists, the owner paused the loop: reply "Paused" and stop.
|
|
79
83
|
Stop if DONE.md or BLOCKED.md exists at the root or in .ai/lanes/${{ matrix.lane }}/.
|
|
84
|
+
If `git pull --ff-only` fails because the clone started from a stale copy, run `git fetch origin main && git switch -C lane-run FETCH_HEAD`, work there, and push with `git push origin HEAD:main`. Never blame a force-push without checking `git log origin/main`.
|
|
85
|
+
Before your final commit of every run (pushed or not), append a line to .ai/lanes/${{ matrix.lane }}/runs.jsonl with `npx compounding-loop runs log --lane ${{ matrix.lane }} --units <units> --passed N --failed N --pushed` (or `--no-pushed`) and include it in that final commit so it is pushed with it.
|
|
86
|
+
If .ai/lanes/${{ matrix.lane }}/claim names someone else and its expiry (name · expires <ISO UTC time>, compared with `date -u`) is in the future, a teammate is working this lane: reply "Nothing to do" and stop. An expired claim counts as none.
|
|
80
87
|
Never publish, spend money, or add secrets or tracking.
|
|
81
88
|
claude_args: >-
|
|
82
89
|
--max-turns 200
|
|
83
90
|
--allowedTools "Bash,Edit,Write,Read,Glob,Grep,Task"
|
|
84
91
|
|
|
92
|
+
control:
|
|
93
|
+
# Optional supervisor: runs the tests, checks lane ownership, unblocks lanes. Full text:
|
|
94
|
+
# runners/routine/control-room-prompt.md. It pushes `.ai/` notes and small fixes, so it needs write access.
|
|
95
|
+
runs-on: ubuntu-latest
|
|
96
|
+
timeout-minutes: 30
|
|
97
|
+
permissions:
|
|
98
|
+
contents: write
|
|
99
|
+
concurrency:
|
|
100
|
+
group: loop-control-room
|
|
101
|
+
cancel-in-progress: false
|
|
102
|
+
steps:
|
|
103
|
+
- name: Is this the control room's turn?
|
|
104
|
+
id: gate
|
|
105
|
+
env:
|
|
106
|
+
EVENT: ${{ github.event_name }}
|
|
107
|
+
FIRED: ${{ github.event.schedule }}
|
|
108
|
+
run: |
|
|
109
|
+
if [ "$EVENT" = "workflow_dispatch" ] || [ "$FIRED" = "47 */3 * * *" ]; then echo "go=true" >> "$GITHUB_OUTPUT"; else echo "go=false" >> "$GITHUB_OUTPUT"; fi
|
|
110
|
+
- uses: actions/checkout@v4
|
|
111
|
+
if: steps.gate.outputs.go == 'true'
|
|
112
|
+
with:
|
|
113
|
+
ref: main
|
|
114
|
+
fetch-depth: 0
|
|
115
|
+
persist-credentials: true
|
|
116
|
+
- uses: actions/setup-node@v4
|
|
117
|
+
if: steps.gate.outputs.go == 'true'
|
|
118
|
+
with:
|
|
119
|
+
node-version: 22
|
|
120
|
+
- uses: anthropics/claude-code-action@v1
|
|
121
|
+
if: steps.gate.outputs.go == 'true'
|
|
122
|
+
with:
|
|
123
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
124
|
+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
125
|
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
126
|
+
# Paste runners/routine/control-room-prompt.md here with {{name}} and {{lanes}} filled. Short form shown:
|
|
127
|
+
prompt: |
|
|
128
|
+
You are the scheduled control room run of an unattended build loop. Read CLAUDE.md and IDEA.md.
|
|
129
|
+
Follow .ai/control-run.md from step 1 (schedule backoff and wake, tests, leak check, lane supervision). In short: pull main, run the tests, run `npx compounding-loop check-lanes` over the last 4 hours, read every lane's task.md and outbox,
|
|
130
|
+
and write notes for lanes in `.ai/control-room.md`. Commit only `.ai/` notes and the smallest fixes, each ending with the trailer line "Lane: control". Push to main.
|
|
131
|
+
If .ai/PAUSED exists, the owner paused the loop: reply "Paused" and stop. Stop if DONE.md or BLOCKED.md exists at the root.
|
|
132
|
+
If `git pull --ff-only` fails because the clone started from a stale copy, run `git fetch origin main && git switch -C lane-run FETCH_HEAD` and push with `git push origin HEAD:main`.
|
|
133
|
+
Never publish, spend money, or add secrets or tracking.
|
|
134
|
+
claude_args: >-
|
|
135
|
+
--max-turns 100
|
|
136
|
+
--allowedTools "Bash,Edit,Write,Read,Glob,Grep,Task"
|
|
137
|
+
|
|
85
138
|
verify:
|
|
86
139
|
# Read-only: reports any commit that crossed a lane boundary.
|
|
87
|
-
needs: lane
|
|
140
|
+
needs: [lane, control]
|
|
88
141
|
if: ${{ always() }}
|
|
89
142
|
runs-on: ubuntu-latest
|
|
90
143
|
timeout-minutes: 10
|
package/runners/local/README.md
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Runs the loop from your own machine on a schedule. Needs Node 20+, git and the `claude` CLI signed in to your account.
|
|
4
4
|
|
|
5
|
-
- **Linux:** paste the line from `crontab.txt` into `crontab -e` and set your repository path.
|
|
5
|
+
- **Linux:** paste the line from `crontab.txt` into `crontab -e` and set your repository path. Prefer systemd? Copy `compounding-loop.service` and `compounding-loop.timer` to `~/.config/systemd/user/`, set `WorkingDirectory`, and enable the timer (commands at the top of the service file); it also runs missed rounds after sleep.
|
|
6
6
|
- **macOS:** `crontab.txt` works too, but launchd is the native scheduler and runs missed rounds after sleep. Edit the paths in `launchd.plist` (`loop` from `which loop`, your repository, the log file), copy it to `~/Library/LaunchAgents/` and load it with the `launchctl bootstrap` line at the top of the file. The plist runs `loop run` hourly at minute 17.
|
|
7
7
|
- **Windows:** edit the path in `task-scheduler.xml`, then import it with `schtasks /Create /XML task-scheduler.xml /TN CompoundingLoop`. The `claude.exe` native build must be on your PATH. Add `--skip-permissions` to the task's arguments only in a repository you trust, so the unattended run can edit files.
|
|
8
8
|
|
|
9
9
|
Both use the minute `17`; change it so several loops do not start together. Each run is capped by the session lock (90 minutes) and the run budget (`Run: N / 30`).
|
|
10
|
+
|
|
11
|
+
**Pausing:** `loop pause` writes `.ai/PAUSED` and `loop resume` removes it. While it exists `loop run` skips the round (and every prompt says "Paused" and stops), so the scheduler can stay enabled. If the repository clone is stale (`git pull --ff-only` fails), the run fetches `origin main` and pushes with `git push origin HEAD:main` instead of blaming a force-push.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Compounding Loop as a systemd user service: one round of `loop run`, started by compounding-loop.timer.
|
|
2
|
+
# Install (replace /path/to/repo and check `which loop`):
|
|
3
|
+
# mkdir -p ~/.config/systemd/user
|
|
4
|
+
# cp compounding-loop.service compounding-loop.timer ~/.config/systemd/user/
|
|
5
|
+
# systemctl --user daemon-reload && systemctl --user enable --now compounding-loop.timer
|
|
6
|
+
# loginctl enable-linger $USER # on a server or VPS, so the timer keeps running after you log out
|
|
7
|
+
# systemctl --user start compounding-loop.service && journalctl --user -u compounding-loop -n 20 # verify now
|
|
8
|
+
# Remove: systemctl --user disable --now compounding-loop.timer
|
|
9
|
+
# systemd's user PATH is minimal: `loop`, `node` and `claude` must all be on the PATH line below (edit it for nvm/volta/fnm).
|
|
10
|
+
# Logs: journalctl --user -u compounding-loop. Add --skip-permissions to ExecStart only in a repository you trust.
|
|
11
|
+
[Unit]
|
|
12
|
+
Description=Compounding Loop: one unattended round
|
|
13
|
+
|
|
14
|
+
[Service]
|
|
15
|
+
Type=oneshot
|
|
16
|
+
WorkingDirectory=/path/to/repo
|
|
17
|
+
Environment=PATH=%h/.local/bin:%h/.npm-global/bin:/usr/local/bin:/usr/bin:/bin
|
|
18
|
+
ExecStart=/usr/bin/env loop run
|
|
19
|
+
# Stop a round before the 90-minute session lock goes stale, so the next hourly start is not blocked.
|
|
20
|
+
TimeoutStartSec=85min
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Runs compounding-loop.service hourly at minute 17 (change it so several loops do not start together).
|
|
2
|
+
# Persistent=true runs a missed round after the machine was asleep, like launchd.
|
|
3
|
+
[Unit]
|
|
4
|
+
Description=Compounding Loop hourly round
|
|
5
|
+
|
|
6
|
+
[Timer]
|
|
7
|
+
OnCalendar=*:17:00
|
|
8
|
+
Persistent=true
|
|
9
|
+
|
|
10
|
+
[Install]
|
|
11
|
+
WantedBy=timers.target
|
|
@@ -27,7 +27,11 @@ With several lanes, create one routine per lane plus one control room routine.
|
|
|
27
27
|
| `lane-prompt.md` | `{{name}}` project, `{{lane}}` lane name | one per lane, hourly |
|
|
28
28
|
| `control-room-prompt.md` | `{{name}}` project, `{{lanes}}` lane names, comma separated | one, every 3 hours |
|
|
29
29
|
|
|
30
|
-
`loop run --lane <name>` fills them for local runs. In the cloud, paste the filled text into the routine. In the cloud nothing writes the lock; it only matters when a local `loop run --lane` is active too. The lane prompt stands down on a fresh `.ai/lanes/<lane>/session.lock`, stops on root or lane `DONE.md`/`BLOCKED.md`, and ends every commit with `Lane: <lane>`.
|
|
30
|
+
`loop run --lane <name>` fills them for local runs. In the cloud, paste the filled text into the routine. In the cloud nothing writes the lock; it only matters when a local `loop run --lane` is active too. The lane prompt stands down on a fresh `.ai/lanes/<lane>/session.lock`, stops on root or lane `DONE.md`/`BLOCKED.md`, stands down when `.ai/lanes/<lane>/claim` names someone else and has not expired (see `loop claim`), and ends every commit with `Lane: <lane>`.
|
|
31
|
+
|
|
32
|
+
### Thin prompts
|
|
33
|
+
|
|
34
|
+
The lane and control room prompts are short on purpose: they do the pull (with the stale-clone recovery) and say "follow `.ai/lane-run.md`" (control room: `.ai/control-run.md`). Everything else (stop checks, `.ai/schedule.json` "Not due" skip, steering in `.ai/lanes/<lane>/steer.md`, the run log, idle backoff) lives in those two files, which come from `templates/lanes/` (copy them into `.ai/`; `loop init --lanes` will write them once core ships the hook). Change how all lanes run with one commit that ends `Lane: control`; the routine settings stay as they are. A repo that predates them needs the two files before the thin prompts work (copy `lane-run.md` and `control-run.md` from `templates/lanes/` to `.ai/`).
|
|
31
35
|
|
|
32
36
|
### Staggered cron for N lanes
|
|
33
37
|
|
|
@@ -1,16 +1,6 @@
|
|
|
1
|
-
You are the scheduled "control room" run for this repository ({{name}}). The lanes ({{lanes}}) push to `main` on their own schedules; you do the supervision the owner would otherwise do by hand. Nobody is watching; the owner reads your final summary later.
|
|
1
|
+
You are the scheduled "control room" run for this repository ({{name}}). The lanes ({{lanes}}) push to `main` on their own schedules; you do the supervision the owner would otherwise do by hand. Nobody is watching; the owner reads your final summary later. Every commit you make ends with the trailer line `Lane: control`.
|
|
2
2
|
|
|
3
|
-
0. Run `date -u`. `git checkout main && git pull --ff-only`.
|
|
4
|
-
1.
|
|
5
|
-
2. Run the install and test commands from CLAUDE.md. If the tests are red: find the commit that broke it (`git log`, `git bisect` only if quick). If the fix is small and obvious, make it, run the tests, commit with the trailer `Lane: control` and push. Otherwise add a note to `.ai/control-room.md` addressed to the owning lane with the failing command and the likely commit. Also check lane ownership: run `git fetch --unshallow` if the clone is shallow, then `npx compounding-loop check-lanes --range <commit from 4 hours ago>..HEAD` (or `loop check-lanes` if installed), and report each violation to the lane that caused it. If the command is unavailable or errors, say so in the summary and carry on.
|
|
6
|
-
3. Leak check: the published package must contain nothing from `.ai/`, the brief, CLAUDE.md or tests (`npm pack --dry-run`, or your project's equivalent). Grep the repository for secrets (API keys, tokens, private keys) and for the owner's email address and local paths. Fix any leak immediately with the smallest change, push, and say so in the summary.
|
|
7
|
-
4. For each lane read `.ai/lanes/<lane>/task.md` (Run counter, Handoff), its outbox, and whether its `DONE.md` or `BLOCKED.md` exists. Then:
|
|
8
|
-
- BLOCKED with "run budget reached": if the lane made real progress (commits that pushed tests or features) and its task file has no line "Budget extended by control room", raise the limit by 20, add that line with the date under Decisions, `git rm` the BLOCKED.md, commit and push. If already extended once, leave it for the owner.
|
|
9
|
-
- BLOCKED with a question: if it can be answered safely from the brief and CLAUDE.md (never anything that spends money, creates accounts, publishes, posts, changes repo visibility or settings, or adds secrets), write the answer under Decisions in that lane's task file as "Answer from control room (date): ...", `git rm` the BLOCKED.md, commit and push. Otherwise leave it and put the question in your summary.
|
|
10
|
-
- A lane waiting on a lane that is already DONE: tell the waiting lane in `.ai/control-room.md` to stop waiting, list the gap as a next improvement in its DONE.md, and finish.
|
|
11
|
-
- A message in any outbox that has waited more than 3 hours for a lane that has since run without answering: copy it into `.ai/control-room.md` addressed to that lane.
|
|
12
|
-
- Lanes with no commit in the last 4 hours and no DONE/BLOCKED: note "stalled" in the summary. Runs that end in about a second are usually a plan or rate limit, not a bug.
|
|
13
|
-
5. When every `.ai/lanes/*/DONE.md` exists, check every line of the brief's "Done when" for the whole product by running its commands. If all pass, write root `DONE.md`: what was built, test results, anything unsure, and the owner's launch checklist. Commit and push. If a line fails, add a note to `.ai/control-room.md` for the owning lane, `git rm` that lane's DONE.md so it resumes, commit and push.
|
|
14
|
-
6. Commit only `.ai/` notes and the smallest fixes, each with the trailer `Lane: control`. End with one line per lane: `lane · Run N/LIMIT · building|blocked|done|stalled · last commit time · note`, then one line for tests and the leak check, then any question for the owner.
|
|
3
|
+
0. Run `date -u`. Run `git checkout main && git pull --ff-only`. If that pull fails because local `main` and `origin/main` have diverged or look unrelated, the clone started from a stale cached copy; origin `main` is never rewritten, so do not report a rewrite and do not reset anything (check `git log origin/main` before blaming a force-push). Instead run `git fetch origin main && git switch -C lane-run FETCH_HEAD`, work on that branch, and wherever the procedure says pull or push, use `git pull --rebase origin main` and `git push origin HEAD:main`. Push only to `main` on origin. Never force-push. Never create or push a `claude/` branch. Verify claims on a fresh pull: a stale clone is not evidence.
|
|
4
|
+
1. Then follow `.ai/control-run.md` from step 1, exactly. It is the procedure (pause and DONE checks, `.ai/schedule.json` backoff and wake, tests, leak check, lane supervision, round check); CLAUDE.md and IDEA.md are the rules and the brief. If `.ai/control-run.md` is missing, you are on a stale clone (redo step 0) or the repo predates it (copy it from the package's `templates/lanes/`, or follow CLAUDE.md directly).
|
|
15
5
|
|
|
16
|
-
Never spend money, sign up for anything, create accounts, publish anything (no package publish, no posting, no repo visibility or settings changes, no releases), add API keys, secrets, ads, analytics or tracking, force-push, or touch anything outside this repository.
|
|
6
|
+
Never spend money, sign up for anything, create accounts, publish anything (no package publish, no posting, no repo visibility or settings changes, no releases, no tags, no version bump), add API keys, secrets, ads, analytics or tracking, force-push, or touch anything outside this repository.
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
You are one scheduled run of the **{{lane}}** lane of an unattended build loop for this repository ({{name}}).
|
|
1
|
+
You are one scheduled run of the **{{lane}}** lane of an unattended build loop for this repository ({{name}}). Other lanes push to the same `main` at other minutes of the hour. Nobody is watching; the owner reads the results later. Your lane is `{{lane}}`; every commit message you write ends with the trailer line `Lane: {{lane}}`.
|
|
2
2
|
|
|
3
|
-
0. Run `date -u` and note it as this run's start time. Run `git checkout main && git pull --ff-only`.
|
|
4
|
-
1.
|
|
5
|
-
2. Run the install command from CLAUDE.md (`npm install` unless it says otherwise). If it fails, write `.ai/lanes/{{lane}}/BLOCKED.md` with the error and stop. If the tests need a browser, install it the way CLAUDE.md says (a blocked download or a Chrome that will not launch is covered under "Commands" there). If CLAUDE.md names no commands, derive them from `package.json` and record them under Decisions.
|
|
6
|
-
3. Read `.ai/control-room.md` and every other lane's `.ai/lanes/*/outbox.md` for messages to {{lane}} or all. Run the resume protocol (.ai/method.md section 9.2) on your task file and add 1 to its run counter. If the counter has reached its limit, follow "Run budget" in CLAUDE.md.
|
|
7
|
-
4. Run the test command from CLAUDE.md (`npm test` unless it says otherwise) on the fresh pull. If it fails, fixing it is your first unit ("main stays green" in CLAUDE.md), whichever lane owns the failure (commit that fix with the trailer `Lane: control`, which `loop check-lanes` allows to touch any path, and tell the owner in your outbox). Otherwise take the next unit: a message addressed to you that another lane is waiting on, else the next item in your task file's units list. Edit only the paths your lane owns, plus the smallest needed edits to shared files. Then run the tests.
|
|
8
|
-
5. Green: commit, have a reviewer subagent check the diff against IDEA.md and your lane contract ("find the three most likely ways this is wrong for a real user, and check each"), fix any blockers, run the tests again, pull, then push to `main`. Run the reviewer in the foreground if you can. If it runs in the background you are resumed when it reports; then finish this step and continue with step 6. Ending your turn ends the run unless a subagent is still running, so never end it to wait for anything else. Red: write the attempt and the reason under Tried in your task file, then discard the unit's uncommitted changes. The same failure twice means the stuck protocol (§9.3); its last step is `.ai/lanes/{{lane}}/BLOCKED.md`.
|
|
9
|
-
6. A pushed unit does not end the run. Go straight back to step 4 with the next unit and keep going until one of these is true: 40 minutes have passed since the start time (check `date -u` after each push), your context is about 60% full, your lane has no units left, or every remaining unit is blocked. Each unit still gets its own tests, review and push.
|
|
10
|
-
7. Then run the handoff (.ai/method.md section 9.1) in your task file so a fresh run with zero memory can continue at full quality, and add a line to your outbox for any lane affected by what you shipped (new types, routes, files they are waiting for). If every done-when in your lane contract passes and the reviewer finds no blockers, follow "Lane finished" in CLAUDE.md instead: read the other lanes' outboxes first, run the retro, write `.ai/lanes/{{lane}}/DONE.md`. Commit, push to `main`, and stop.
|
|
3
|
+
0. Run `date -u` and note it as this run's start time. Run `git checkout main && git pull --ff-only`. If that pull fails because local `main` and `origin/main` have diverged or look unrelated, the clone started from a stale cached copy; origin `main` is never rewritten, so do not report a rewrite and do not reset anything (check `git log origin/main` before blaming a force-push). Instead run `git fetch origin main && git switch -C lane-run FETCH_HEAD`, work on that branch, and wherever the procedure says pull or push, use `git pull --rebase origin main` and `git push origin HEAD:main`. Push only to `main` on origin. Never force-push. Never create or push a `claude/` branch. If pushing to main is refused by permissions, push to a branch named `claude/{{lane}}-blocked` and stop.
|
|
4
|
+
1. Then follow `.ai/lane-run.md` from step 1, exactly, with `<lane>` = `{{lane}}`. It is the run procedure (stop checks: `.ai/PAUSED`, DONE/BLOCKED, claim, `.ai/schedule.json` "Not due"; steering in `.ai/lanes/{{lane}}/steer.md`; the run log in `.ai/lanes/{{lane}}/runs.jsonl`); CLAUDE.md (lane table, hard rules, Unattended mode) and IDEA.md are the rules and the brief. Its first step is a cheap stop check: if it says stop, stop at once without installing anything. If `.ai/lane-run.md` is missing, you are on a stale clone (redo step 0) or the repo predates it (copy it from the package's `templates/lanes/`, or follow CLAUDE.md directly).
|
|
11
5
|
|
|
12
|
-
Never spend money, sign up for anything, create accounts, publish anything (no package publish, no posting, no repo visibility or settings changes, no releases, no version bump), add API keys, secrets, ads, analytics or tracking,
|
|
6
|
+
Never spend money, sign up for anything, create accounts, publish anything (no package publish, no posting, no repo visibility or settings changes, no releases, no tags, no version bump), add API keys, secrets, ads, analytics or tracking, force-push, or touch anything outside this repository.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
You are one scheduled run of the build loop for this repository ({{name}}). Nobody is watching; the owner reads the results later. Read CLAUDE.md and follow it exactly, especially "Unattended mode". IDEA.md is the brief. Your task file is `.ai/task.md`.
|
|
2
2
|
|
|
3
|
-
0. Run `date -u` and note it as this run's start time. Run `git checkout main && git pull --ff-only`. Every commit goes to `main` and is pushed with `git push origin main`. Never create or push a `claude/` branch: the next run starts from `main` and would never see it. If a push is rejected, run `git pull --rebase`, re-run the checks if incoming commits touched code, and push again.
|
|
3
|
+
0. Run `date -u` and note it as this run's start time. Run `git checkout main && git pull --ff-only`. If that pull fails because local `main` and `origin/main` have diverged or look unrelated, the sandbox started from a stale cached clone; origin `main` is never rewritten, so do not reset anything: run `git fetch origin main && git switch -c lane-run FETCH_HEAD`, work there, and wherever these steps say pull or push use `git pull --rebase origin main` and `git push origin HEAD:main`. Every commit goes to `main` and is pushed with `git push origin main`. Never create or push a `claude/` branch: the next run starts from `main` and would never see it. If a push is rejected, run `git pull --rebase`, re-run the checks if incoming commits touched code, and push again.
|
|
4
4
|
1. Session lock: if `.ai/session.lock` holds a UTC time less than 90 minutes old, another session owns the repo, unless the lock is your own (the runner's run note says so when the loop runner created it). Otherwise reply "Nothing to do" and stop. If the file is older than that, it is stale: ignore it.
|
|
5
|
-
2. If `DONE.md` or `BLOCKED.md` exists, reply "Nothing to do" and stop.
|
|
5
|
+
2. If `DONE.md` or `BLOCKED.md` exists, reply "Nothing to do" and stop. Pause: if `.ai/PAUSED` exists, the owner paused the loop: reply "Paused" and stop.
|
|
6
6
|
3. Run the install command from CLAUDE.md (`npm install` unless it says otherwise). If it fails, write `BLOCKED.md` with the error and stop.
|
|
7
7
|
4. If `.ai/task.md` exists, run the resume protocol (.ai/method.md §9.2) and add 1 to its `Run: N / 30` counter. When the counter reaches 30, write `BLOCKED.md` saying "run budget reached", push, and stop. If there is no task file, write one from IDEA.md first.
|
|
8
8
|
5. Run the test command from CLAUDE.md (`npm test` unless it says otherwise) on the fresh pull. If it fails, fixing it is your first unit ("main stays green"). Otherwise take the next unit from the task file. Do one unit at a time.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Lane templates
|
|
2
2
|
|
|
3
|
-
Files `loop init --lanes` copies into a repository that runs several lanes. A lane is one scheduled run that owns one part of the codebase (see `method/COMPOUNDING_LOOP.md`, chapter "Lanes").
|
|
3
|
+
Files `loop init --lanes` copies (the four run-model files `lane-run.md`, `control-run.md`, `schedule.json`, `steer.md` once core ships that hook; until then copy them by hand) into a repository that runs several lanes. A lane is one scheduled run that owns one part of the codebase (see `method/COMPOUNDING_LOOP.md`, chapter "Lanes").
|
|
4
4
|
|
|
5
5
|
| File | Written to | Once per |
|
|
6
6
|
|---|---|---|
|
|
@@ -9,6 +9,10 @@ Files `loop init --lanes` copies into a repository that runs several lanes. A la
|
|
|
9
9
|
| `control-room.md` | `.ai/control-room.md` | repo |
|
|
10
10
|
| `claude-section.md` | appended to `CLAUDE.md` and `AGENTS.md`; `loop init --lanes` wraps it in its own markers, so a second run replaces the block | repo |
|
|
11
11
|
| `ci-check-lanes.yml` | `.github/workflows/check-lanes.yml` | repo |
|
|
12
|
+
| `lane-run.md` | `.ai/lane-run.md` | repo: the run procedure every lane routine prompt points at (stop checks incl. "Not due", steering, run log, idle backoff) |
|
|
13
|
+
| `control-run.md` | `.ai/control-run.md` | repo: the control room's procedure (schedule backoff and wake, tests, leak check, supervision) |
|
|
14
|
+
| `schedule.json` | `.ai/schedule.json` | repo: `{"version":1,"lanes":{}}`; a missing lane entry means due |
|
|
15
|
+
| `steer.md` | `.ai/lanes/<lane>/steer.md` | lane |
|
|
12
16
|
|
|
13
17
|
## Placeholders
|
|
14
18
|
|
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
This repository is built by parallel **lanes**. Lanes in this repo: {{lanes}}. Each lane is a scheduled run that owns one part of the codebase. `.ai/lanes.json` says which paths each lane owns and which files are shared; read it first. Each lane's task file is `.ai/lanes/<lane>/task.md`.
|
|
4
4
|
|
|
5
|
+
- **Run procedure:** a lane run follows `.ai/lane-run.md` (the control room: `.ai/control-run.md`); the routine prompt only names the lane and does the pull. It holds the cheap stop checks (a lane that is paused, sleeping or before its `notBefore` in `.ai/schedule.json` replies "Not due" and stops before the install), the steering step (`.ai/lanes/<your lane>/steer.md`: `next-run` entries first, `standing` entries until removed, each acknowledged with one `→` line), the run log and the idle backoff. Only `Lane: control` commits change those two files.
|
|
5
6
|
- **Edit only the paths your lane owns.** Read anything. **Shared files** (`shared` in `.ai/lanes.json`) may be edited by any lane, with the smallest possible edit.
|
|
6
7
|
- **Commit trailer:** every commit message ends with a line `Lane: <your lane>` (the control room uses `Lane: control`). `loop check-lanes` fails a commit that touches another lane's paths.
|
|
7
8
|
- **Talking to other lanes:** write only to your own `.ai/lanes/<you>/outbox.md`, newest first, `YYYY-MM-DD HH:MM UTC · to <lane|all> · message`. At the start of each run read every other lane's outbox and `.ai/control-room.md` for messages to you or `all`, and act on them or say in your task file why not.
|
|
8
9
|
- **Main stays green.** If the tests fail on a fresh pull before you change anything, fixing that is your first unit, whichever lane owns the failure. Make the smallest fix, commit it with the trailer `Lane: control` (the only trailer `loop check-lanes` lets touch any path), and tell the owning lane in your outbox.
|
|
9
|
-
- **Git:** work on `main`. Start every run with `git checkout main && git pull --ff-only`, pull again right before each push, and on a rejected push `git pull --rebase`. If a rebase conflicts in a file you do not own, `git rebase --abort`, record it under Tried, pull fresh, redo your small change on top. Never force-push.
|
|
10
|
+
- **Git:** work on `main`. Start every run with `git checkout main && git pull --ff-only`, pull again right before each push, and on a rejected push `git pull --rebase`. If a rebase conflicts in a file you do not own, `git rebase --abort`, record it under Tried, pull fresh, redo your small change on top. Never force-push. If `git pull --ff-only` fails because the clone started from a stale cached copy (local `main` and `origin/main` diverged or unrelated), origin `main` was not rewritten: check `git log origin/main`, run `git fetch origin main && git switch -C lane-run FETCH_HEAD`, work on that branch, and from then on pull with `git pull --rebase origin main` and push with `git push origin HEAD:main`.
|
|
11
|
+
- **Run log:** every run that gets past the stop checks ends, pushed or not (also on failing tests or BLOCKED), by appending one line to `.ai/lanes/<your lane>/runs.jsonl` with `loop runs log --lane <your lane> --units <unit names> --passed N --failed N --pushed` (or `--no-pushed`, optionally `--note "why"`), committed in your final commit, so it is pushed with it. The dashboard shows a scheduled slot with no line and no commit as "no run recorded".
|
|
10
12
|
- **Run budget:** your lane's task file holds `Run: N / LIMIT`. Add 1 at the start of every run; at the limit write `.ai/lanes/<lane>/BLOCKED.md` ("run budget reached") and stop.
|
|
13
|
+
- **Pause:** if `.ai/PAUSED` exists, the owner paused the loop (`loop pause` writes it, `loop resume` removes it): reply "Paused" and stop. The control room stops too.
|
|
11
14
|
- **Stop files:** if root `DONE.md` or `BLOCKED.md`, or your lane's `DONE.md` or `BLOCKED.md`, exists at the start of a run, do nothing and stop. A lane writes its own `DONE.md` when every done-when in its contract passes and the reviewer finds no blockers. Root `DONE.md` is written only by the control room.
|
|
15
|
+
- **Claims:** if `.ai/lanes/<your lane>/claim` exists (one line, `name · expires <UTC time>`), names someone other than you (a scheduled run has no name, so any unexpired claim stops it), and its expiry (an ISO UTC timestamp, compared with `date -u`) is in the future, a teammate is working that lane: reply "Nothing to do" and stop. An expired claim counts as none (leave the file; `loop claim` overwrites it).
|
|
12
16
|
- **Stuck:** the same failure twice means the stuck protocol; its last step is the lane's `BLOCKED.md` with what you tried, the specific question and your best guess.
|
|
13
17
|
- **Review before every push to `main`:** the tests must pass, then a reviewer subagent that did not write the code checks the diff against the brief ("find the three most likely ways this is wrong for a real user, and check each"). Fix blockers first.
|
|
14
18
|
- **Questions:** no human is watching. Decide from the brief and common sense, write the decision and the reason under **Decisions** in your task file, and pick the option that is easiest to reverse.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Control room run procedure
|
|
2
|
+
|
|
3
|
+
The control room routine's prompt says "follow `.ai/control-run.md`". The prompt itself does step 0 (pull, stale clone). You do the supervision the owner would otherwise do by hand. Be brief and cheap. Read CLAUDE.md (lane table, hard rules, Unattended mode) and IDEA.md (the current brief, with its "done when" list and any deadline). Every commit you make ends with the trailer line `Lane: control`.
|
|
4
|
+
|
|
5
|
+
1. If root `DONE.md` exists, give the summary (step 7) and stop. If `.ai/PAUSED` exists, reply "Paused" and stop.
|
|
6
|
+
2. **Schedule** (cheap, before the install). Read `.ai/schedule.json`, each lane's `runs.jsonl`, `steer.md`, outbox and `.ai/control-room.md`.
|
|
7
|
+
- Run `npx compounding-loop schedule update` if your installed version has it. Otherwise apply the rule by hand:
|
|
8
|
+
- backoff for idle lanes;
|
|
9
|
+
- **wake** a lane that is sleeping or waiting on `notBefore` (`sleeping: false`, `notBefore: null`) when it has a steer entry with no `→` line, or a message addressed to it newer than its last run.
|
|
10
|
+
- Never change `paused` (only the owner pauses a lane).
|
|
11
|
+
- If nothing else in this run needs work, commit any schedule change and skip to step 7. "Nothing else" means: no lane committed since your last run, and no lane has DONE.md that hasn't been checked yet.
|
|
12
|
+
3. Run the install and test commands from CLAUDE.md (`npm install` and `npm test` unless it says otherwise).
|
|
13
|
+
- If it is red, find the commit that broke it (`git log`, `git bisect` only if quick).
|
|
14
|
+
- If the fix is small and obvious, make it, run the tests, commit and push.
|
|
15
|
+
- Otherwise add a note to `.ai/control-room.md` addressed to the owning lane, with the failing command and the likely commit.
|
|
16
|
+
4. **Leak check:**
|
|
17
|
+
- If the project publishes a package, a dry-run pack (`npm pack --dry-run` or your equivalent) must list nothing from `.ai/`, the brief, `CLAUDE.md` or `tests/`.
|
|
18
|
+
- Grep the repo for secrets (API keys, tokens, private keys) and for the owner's email address. Fix any leak immediately (smallest change), push, and say so in the summary.
|
|
19
|
+
- Run `npx compounding-loop check-lanes` over the commits since your last run and tell each lane that crossed its paths in `.ai/control-room.md`.
|
|
20
|
+
5. For each lane, read `.ai/lanes/<lane>/task.md` (run counter, handoff), its outbox, `.ai/audit/<lane>.md` (open blockers in the current round's section), and whether `.ai/lanes/<lane>/DONE.md`, `BLOCKED.md` or an unexpired `claim` exists. Then:
|
|
21
|
+
- **BLOCKED with "run budget reached":** if the lane made real progress (commits that pushed tests or features) and its task file has no line "Budget extended by control room", raise the limit by 15, add that line with the date under Decisions, `git rm` the BLOCKED.md, commit, push. If it was already extended once, leave it for the owner.
|
|
22
|
+
- **BLOCKED with a question:** if it can be answered safely from IDEA.md and CLAUDE.md (never anything that spends money, creates accounts, publishes, posts, changes repo visibility or settings, or adds secrets), write the answer under Decisions in that lane's task file as "Answer from control room (date): ...", `git rm` the BLOCKED.md, commit, push. Otherwise leave it and put the question in your summary for the owner.
|
|
23
|
+
- **A message waiting in an outbox:** if it has waited more than 3 hours for a lane that has since run without answering, copy it into `.ai/control-room.md` addressed to that lane, and wake that lane. If the lane it waits on has DONE.md, tell the waiting lane to stop waiting and either work around it or list it as a next improvement.
|
|
24
|
+
- **Stalled lanes:** a lane that is due in schedule.json, has no runs.jsonl line in the last 4 hours, no DONE/BLOCKED and no unexpired claim is "stalled" in the summary (likely the plan's five-hour usage limit). A lane that isn't due is "sleeping" or "not due until <time>", not stalled. A lane with an unexpired claim is "claimed by <name>".
|
|
25
|
+
- **After the deadline** of the current round in IDEA.md: tell every lane without DONE.md, once, in `.ai/control-room.md`, to finish its open unit, start nothing new and write DONE.md. Wake those lanes.
|
|
26
|
+
6. **Round check:** when every lane in `.ai/lanes.json` has a `.ai/lanes/<lane>/DONE.md`, check every line of the current round's "done when" list in IDEA.md by running its commands. Run the fresh-install check the list names (for a package: pack it, install it in an empty temp dir, follow the README quick start word for word).
|
|
27
|
+
- If all pass, write root `DONE.md`, then commit and push. It contains:
|
|
28
|
+
- what was built and the test results;
|
|
29
|
+
- the minor audit findings left open (from `.ai/audit/*.md`) and anything unsure;
|
|
30
|
+
- the owner's release checklist: the owner bumps the version, finalises the changelog, runs the tests and publishes; the control room never publishes.
|
|
31
|
+
- If a line fails, add a note to `.ai/control-room.md` for the owning lane, `git rm` that lane's DONE.md so it resumes, wake that lane, commit and push.
|
|
32
|
+
7. Commit only `.ai/` notes, `.ai/schedule.json` and the smallest fixes. End with:
|
|
33
|
+
- one line per lane: `lane · Run N/LIMIT · building|sleeping|not due until T|blocked|done|stalled|claimed · last run · open blockers · note`;
|
|
34
|
+
- one line for tests and the leak check;
|
|
35
|
+
- any question for the owner.
|
|
36
|
+
|
|
37
|
+
Never spend money, sign up for anything, create accounts, publish anything (no npm publish, no posting, no repo visibility or settings changes, no releases, no tags, no version bump), add API keys, secrets, ads, analytics or tracking, force-push, or touch anything outside this repository.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Lane run procedure
|
|
2
|
+
|
|
3
|
+
Every lane routine's prompt names its lane `<lane>` and says "follow `.ai/lane-run.md`". The prompt itself does step 0 (pull, stale clone). This file is the rest. Change it with a commit that ends `Lane: control`; lane runs never edit it. Wherever the Operating Card or `.ai/method.md` says `.ai/task.md`, use `.ai/lanes/<lane>/task.md`. Every commit message you write ends with the trailer line `Lane: <lane>`.
|
|
4
|
+
|
|
5
|
+
1. **Cheap stop checks. Do these before anything else, with no `npm install`.** Reply with the word in quotes and stop, without committing:
|
|
6
|
+
- root `DONE.md` or `BLOCKED.md`, or `.ai/lanes/<lane>/DONE.md` or `BLOCKED.md` exists → "Nothing to do";
|
|
7
|
+
- `.ai/PAUSED` exists → "Paused";
|
|
8
|
+
- `.ai/lanes/<lane>/claim` names someone else and its expiry is in the future → "Nothing to do";
|
|
9
|
+
- in `.ai/schedule.json`, your lane's entry has `paused: true`, `sleeping: true`, or a `notBefore` later than now → "Not due". A missing file or a missing entry means due.
|
|
10
|
+
2. Run the install command from CLAUDE.md (`npm install` unless it says otherwise), and install the browser the way CLAUDE.md says if the tests need one. If the install fails, write `.ai/lanes/<lane>/BLOCKED.md` with the error and stop.
|
|
11
|
+
3. Read `.ai/control-room.md` and every other lane's `.ai/lanes/*/outbox.md` for messages to `<lane>` or all. Read `.ai/lanes/<lane>/steer.md` (if it exists): the entries with no `→` line under them are this run's steering. `next-run` entries are done before anything else in step 4. `standing` entries apply to everything you do until the owner removes them. Run the resume protocol (.ai/method.md section 9.2) on your task file and add 1 to its run counter. If the counter has reached its limit, follow "Run budget" in CLAUDE.md.
|
|
12
|
+
4. Run the test command from CLAUDE.md (`npm test` unless it says otherwise) on the fresh pull. If it fails, fixing it is your first unit ("main stays green" in CLAUDE.md). Otherwise take the next unit in this order:
|
|
13
|
+
1. an unacknowledged `next-run` steer entry;
|
|
14
|
+
2. a message addressed to you that another lane is waiting on;
|
|
15
|
+
3. the next item in your task file's units list.
|
|
16
|
+
|
|
17
|
+
A steer entry that conflicts with IDEA.md's hard rules or "Never" list is not done: acknowledge it with the reason. Edit only the paths your lane owns, plus the smallest needed edits to shared files. Then run the tests.
|
|
18
|
+
5. Green: commit, have a reviewer subagent check the diff against IDEA.md, your lane contract and any steer entry it answers. Fix any blockers, run the tests again, pull, then push to `main`. Run the reviewer in the foreground if you can. If it runs in the background you are resumed when it reports; then finish this step and continue with step 6. Ending your turn ends the run unless a subagent is still running, so never end it to wait for anything else. Red: write the attempt and the reason under Tried in your task file, then discard the unit's uncommitted changes.
|
|
19
|
+
6. A pushed unit does not end the run. Go straight back to step 4 with the next unit. Keep going until one of these is true:
|
|
20
|
+
- 40 minutes have passed since the start time (check `date -u` after each push);
|
|
21
|
+
- your context is about 60% full;
|
|
22
|
+
- your lane has no units left;
|
|
23
|
+
- every remaining unit is blocked.
|
|
24
|
+
|
|
25
|
+
This replaces the "when a unit is done" handoff trigger in .ai/method.md. Each unit still gets its own tests, review and push.
|
|
26
|
+
7. Acknowledge every steer entry you read in step 3, by adding exactly one line directly under it: `→ done in run N` or `→ not done: <why>`. Do this for a `standing` entry only once, the first time you read it. This is the only edit you make to `steer.md`. Then run the handoff (.ai/method.md section 9.1) in your task file, so that a fresh run with zero memory can continue at full quality. Add a line to your outbox for any lane affected by what you shipped (new types, routes, files they are waiting for). If every done-when in your lane contract passes, follow "Lane finished" in CLAUDE.md.
|
|
27
|
+
8. **Always, even when the run did nothing**, do two things before the last commit:
|
|
28
|
+
- Append one line to `.ai/lanes/<lane>/runs.jsonl`. Use `npx compounding-loop runs log --lane <lane> --units <names> --passed N --failed N --pushed|--no-pushed [--note …]`, or write this JSON shape by hand: `{"at":ISO,"lane":"<lane>","units":[…],"tests":{"passed":N,"failed":N},"pushed":bool,"note":"…"}`.
|
|
29
|
+
- If this run shipped no unit, apply the idle backoff to **your own entry only** in `.ai/schedule.json`. Use `npx compounding-loop schedule update` if your installed version has it. Otherwise apply the rule by hand: count your trailing idle runs in runs.jsonl. With 1, set `notBefore` to now + 3 h. With 2, set it to now + 6 h. With 3 or more, set `sleeping: true`. Set `reason` to a few words. If your lane's DONE.md now exists, leave schedule.json alone.
|
|
30
|
+
|
|
31
|
+
Then commit, push to `main`, and stop.
|
|
32
|
+
|
|
33
|
+
Never spend money, sign up for anything, create accounts, publish anything (no npm publish, no posting, no repo visibility or settings changes, no releases, no tags, no version bump, no `release.yml` dispatch), add API keys, secrets, ads, analytics or tracking, copy other projects' content without a compatible licence, force-push, edit `.ai/lane-run.md` or `.ai/control-run.md`, or touch anything outside this repository.
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
# Steering for the {{lane}} lane
|
|
2
|
+
|
|
3
|
+
Notes from the owner or a teammate, newest first. Entry format: `## YYYY-MM-DD HH:MM UTC · <author> · next-run|standing`, then the text. The lane adds one line under each entry it has read: `→ done in run N` or `→ not done: <why>` (see `.ai/lane-run.md` steps 3 and 7). Write entries with `loop steer`, the dashboard's Steer button, or by hand.
|
package/templates/lanes/task.md
CHANGED
|
@@ -33,4 +33,4 @@ Status: not started
|
|
|
33
33
|
- Change the Operating Card, the version, or publish anything.
|
|
34
34
|
|
|
35
35
|
## Handoff
|
|
36
|
-
<Rewritten at the end of every run: commit, whether the tree is clean, the single next step, what to read first.>
|
|
36
|
+
<Rewritten at the end of every run: commit, whether the tree is clean, the single next step, what to read first. Name finished units as "units 1-3 done" so `loop next` can skip them, and list what you shipped that another lane waits on (also in your outbox).>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
You are one run of an unattended build loop for this repository. Nobody is watching. Follow CLAUDE.md exactly, especially "Unattended mode".
|
|
2
2
|
|
|
3
|
-
0. Run `git checkout main && git pull --ff-only`. Every commit in this run goes to `main` and is pushed with `git push origin main`. Never push to a `claude/` branch: the next run starts from `main` and would never see it.
|
|
3
|
+
0. Run `git checkout main && git pull --ff-only`. If the pull fails because the clone started from a stale copy (diverged or unrelated history), origin `main` was not rewritten: run `git fetch origin main && git switch -C loop-run FETCH_HEAD`, work there, and push with `git push origin HEAD:main`. Then, on the fresh code: if `.ai/PAUSED` exists, the owner paused the loop: reply "Paused" and stop. Every commit in this run goes to `main` and is pushed with `git push origin main`. Never push to a `claude/` branch: the next run starts from `main` and would never see it.
|
|
4
4
|
1. If `.ai/session.lock` holds a UTC time less than 90 minutes old, another session owns the repo (unless the lock is your own: the run note at the end of this prompt says so when the loop runner created it): reply "Nothing to do" and stop. If `DONE.md` or `BLOCKED.md` exists, reply "Nothing to do" and stop.
|
|
5
5
|
2. Run `npm install`, then `npx playwright install chromium`. If the download is blocked, see "Commands" in CLAUDE.md.
|
|
6
6
|
3. If `.ai/task.md` exists, run the resume protocol (.ai/method.md §9.2) and add 1 to its `Run: N / 30` counter. If the counter has reached its limit, follow "Run budget" in CLAUDE.md. Otherwise start the task from IDEA.md.
|