[{"data":1,"prerenderedAt":718},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fv2\u002Fcognets\u002Ffolder\u002Fplugins":3},{"id":4,"title":5,"body":6,"description":711,"extension":712,"meta":713,"navigation":300,"path":714,"seo":715,"stem":716,"__hash__":717},"docs\u002Fdocs\u002Fv2\u002Fcognets\u002Ffolder\u002Fplugins.md","plugins",{"type":7,"value":8,"toc":699},"minimark",[9,12,16,201,225,230,239,242,249,255,258,450,457,473,480,483,486,492,495,531,534,541,544,624,635,648,652,658,692,695],[10,11,5],"h1",{"id":5},[13,14,15],"p",{},"Four fixed lifecycle points, wired to non-cognitive work: hydrating the resident model,\nwarming a cache, checkpointing on the way out.",[17,18,23],"pre",{"className":19,"code":20,"language":21,"meta":22,"style":22},"language-ts shiki shiki-themes dark-plus","export default definePlugin(({ hooks }) => {\n    hooks.on(\"boot\", async () => { \u002F* once, after load, before the first wake *\u002F })\n    hooks.on(\"wake\", async wake => { \u002F* each wake, before the first tick *\u002F })\n    hooks.on(\"tick\", async ({ tick }) => { \u002F* each tick — keep this cheap *\u002F })\n    hooks.on(\"shutdown\", async () => { \u002F* once, at unload *\u002F })\n})\n","ts","",[24,25,26,60,100,131,166,195],"code",{"__ignoreMap":22},[27,28,31,35,38,42,46,50,53,57],"span",{"class":29,"line":30},"line",1,[27,32,34],{"class":33},"sYbnZ","export",[27,36,37],{"class":33}," default",[27,39,41],{"class":40},"sCudf"," definePlugin",[27,43,45],{"class":44},"sTNBD","(({ ",[27,47,49],{"class":48},"s3F5K","hooks",[27,51,52],{"class":44}," }) ",[27,54,56],{"class":55},"scz_3","=>",[27,58,59],{"class":44}," {\n",[27,61,63,66,69,72,75,79,82,85,88,90,93,97],{"class":29,"line":62},2,[27,64,65],{"class":48},"    hooks",[27,67,68],{"class":44},".",[27,70,71],{"class":40},"on",[27,73,74],{"class":44},"(",[27,76,78],{"class":77},"sKc5r","\"boot\"",[27,80,81],{"class":44},", ",[27,83,84],{"class":55},"async",[27,86,87],{"class":44}," () ",[27,89,56],{"class":55},[27,91,92],{"class":44}," { ",[27,94,96],{"class":95},"sOLPB","\u002F* once, after load, before the first wake *\u002F",[27,98,99],{"class":44}," })\n",[27,101,103,105,107,109,111,114,116,118,121,124,126,129],{"class":29,"line":102},3,[27,104,65],{"class":48},[27,106,68],{"class":44},[27,108,71],{"class":40},[27,110,74],{"class":44},[27,112,113],{"class":77},"\"wake\"",[27,115,81],{"class":44},[27,117,84],{"class":55},[27,119,120],{"class":48}," wake",[27,122,123],{"class":55}," =>",[27,125,92],{"class":44},[27,127,128],{"class":95},"\u002F* each wake, before the first tick *\u002F",[27,130,99],{"class":44},[27,132,134,136,138,140,142,145,147,149,152,155,157,159,161,164],{"class":29,"line":133},4,[27,135,65],{"class":48},[27,137,68],{"class":44},[27,139,71],{"class":40},[27,141,74],{"class":44},[27,143,144],{"class":77},"\"tick\"",[27,146,81],{"class":44},[27,148,84],{"class":55},[27,150,151],{"class":44}," ({ ",[27,153,154],{"class":48},"tick",[27,156,52],{"class":44},[27,158,56],{"class":55},[27,160,92],{"class":44},[27,162,163],{"class":95},"\u002F* each tick — keep this cheap *\u002F",[27,165,99],{"class":44},[27,167,169,171,173,175,177,180,182,184,186,188,190,193],{"class":29,"line":168},5,[27,170,65],{"class":48},[27,172,68],{"class":44},[27,174,71],{"class":40},[27,176,74],{"class":44},[27,178,179],{"class":77},"\"shutdown\"",[27,181,81],{"class":44},[27,183,84],{"class":55},[27,185,87],{"class":44},[27,187,56],{"class":55},[27,189,92],{"class":44},[27,191,192],{"class":95},"\u002F* once, at unload *\u002F",[27,194,99],{"class":44},[27,196,198],{"class":29,"line":197},6,[27,199,200],{"class":44},"})\n",[13,202,203,204,207,208,212,213,216,217,220,221,224],{},"Files in ",[24,205,206],{},"plugins\u002F"," are imported by the compile step ",[209,210,211],"em",{},"after"," the host installs the\nglobals, so a plugin's ",[24,214,215],{},"hooks.on(...)"," registrations land before ",[24,218,219],{},"load()"," fires ",[24,222,223],{},"boot",".\nHooks are awaited to completion, in registration order.",[226,227,229],"h2",{"id":228},"the-rule","The rule",[231,232,233],"blockquote",{},[13,234,235],{},[236,237,238],"strong",{},"Plumbing only. Cognition never lives here.",[13,240,241],{},"That line is worth taking literally. Domain facts are stimuli that fold into the model\nthrough the ordinary path — they do not arrive through hooks. If a plugin is making\ndecisions, the decision belongs in the loop.",[13,243,244,245,248],{},"The distinction is what keeps ",[24,246,247],{},"main.ts"," honest as a description of how the brain thinks.\nA reader who understands your loop should not be surprised by something a hook did.",[226,250,252,254],{"id":251},"boot-hydrate",[24,253,223],{}," — hydrate",[13,256,257],{},"Fires once: brain assembled, kernel bound, loop declared, not yet woken. This is where a\ncold start becomes a warm one.",[17,259,261],{"className":19,"code":260,"language":21,"meta":22,"style":22},"hooks.on(\"boot\", async () => {\n    sync()   \u002F\u002F fold the entire log into the resident model\n\n    const checkpoint = await kernel.store.get(\"checkpoint\")\n    kernel.emit(\"cognet:log:info\", {\n        value: checkpoint\n            ? `hydrated ${state.entries.length} entries (checkpoint seq ${checkpoint.seq})`\n            : `cold boot, hydrated ${state.entries.length} entries`,\n    })\n})\n",[24,262,263,285,296,302,338,356,364,410,439,445],{"__ignoreMap":22},[27,264,265,267,269,271,273,275,277,279,281,283],{"class":29,"line":30},[27,266,49],{"class":48},[27,268,68],{"class":44},[27,270,71],{"class":40},[27,272,74],{"class":44},[27,274,78],{"class":77},[27,276,81],{"class":44},[27,278,84],{"class":55},[27,280,87],{"class":44},[27,282,56],{"class":55},[27,284,59],{"class":44},[27,286,287,290,293],{"class":29,"line":62},[27,288,289],{"class":40},"    sync",[27,291,292],{"class":44},"()   ",[27,294,295],{"class":95},"\u002F\u002F fold the entire log into the resident model\n",[27,297,298],{"class":29,"line":102},[27,299,301],{"emptyLinePlaceholder":300},true,"\n",[27,303,304,307,311,314,317,320,322,325,327,330,332,335],{"class":29,"line":133},[27,305,306],{"class":55},"    const",[27,308,310],{"class":309},"s9McN"," checkpoint",[27,312,313],{"class":44}," = ",[27,315,316],{"class":33},"await",[27,318,319],{"class":48}," kernel",[27,321,68],{"class":44},[27,323,324],{"class":48},"store",[27,326,68],{"class":44},[27,328,329],{"class":40},"get",[27,331,74],{"class":44},[27,333,334],{"class":77},"\"checkpoint\"",[27,336,337],{"class":44},")\n",[27,339,340,343,345,348,350,353],{"class":29,"line":168},[27,341,342],{"class":48},"    kernel",[27,344,68],{"class":44},[27,346,347],{"class":40},"emit",[27,349,74],{"class":44},[27,351,352],{"class":77},"\"cognet:log:info\"",[27,354,355],{"class":44},", {\n",[27,357,358,361],{"class":29,"line":197},[27,359,360],{"class":48},"        value:",[27,362,363],{"class":48}," checkpoint\n",[27,365,367,370,373,376,379,381,384,386,389,392,395,397,400,402,405,407],{"class":29,"line":366},7,[27,368,369],{"class":44},"            ? ",[27,371,372],{"class":77},"`hydrated ",[27,374,375],{"class":55},"${",[27,377,378],{"class":48},"state",[27,380,68],{"class":44},[27,382,383],{"class":48},"entries",[27,385,68],{"class":44},[27,387,388],{"class":48},"length",[27,390,391],{"class":55},"}",[27,393,394],{"class":77}," entries (checkpoint seq ",[27,396,375],{"class":55},[27,398,399],{"class":48},"checkpoint",[27,401,68],{"class":44},[27,403,404],{"class":48},"seq",[27,406,391],{"class":55},[27,408,409],{"class":77},")`\n",[27,411,413,416,419,421,423,425,427,429,431,433,436],{"class":29,"line":412},8,[27,414,415],{"class":44},"            : ",[27,417,418],{"class":77},"`cold boot, hydrated ",[27,420,375],{"class":55},[27,422,378],{"class":48},[27,424,68],{"class":44},[27,426,383],{"class":48},[27,428,68],{"class":44},[27,430,388],{"class":48},[27,432,391],{"class":55},[27,434,435],{"class":77}," entries`",[27,437,438],{"class":44},",\n",[27,440,442],{"class":29,"line":441},9,[27,443,444],{"class":44},"    })\n",[27,446,448],{"class":29,"line":447},10,[27,449,200],{"class":44},[13,451,452,453,456],{},"Nothing is passed in. The cognet reads what it wants through ",[24,454,455],{},"kernel.store.session.get()","\n— for a log-derived mind, that call is the whole rehydration story.",[13,458,459,460,463,464,467,468,68],{},"Note that ",[24,461,462],{},"sync()"," here is the same function the loop calls every tick. Boot isn't a\nspecial path; it's the ordinary fold with the cursor still at ",[24,465,466],{},"-1",". See\n",[469,470,472],"a",{"href":471},"\u002Fdocs\u002Fv2\u002Fcognets\u002Fengine\u002Fmemory","Memory",[226,474,476,479],{"id":475},"wake-per-episode",[24,477,478],{},"wake"," — per episode",[13,481,482],{},"Fires at the start of every wake, before the first tick, and receives the wake context.\nUse it for per-episode setup that isn't part of thinking — resetting a scratch buffer,\nstarting a timer.",[13,484,485],{},"Most cognets don't need it.",[226,487,489,491],{"id":488},"tick-the-hot-path",[24,490,154],{}," — the hot path",[13,493,494],{},"Fires before each iteration of the loop body.",[17,496,498],{"className":19,"code":497,"language":21,"meta":22,"style":22},"hooks.on(\"tick\", async ({ tick }) => { \u002F* keep this cheap *\u002F })\n",[24,499,500],{"__ignoreMap":22},[27,501,502,504,506,508,510,512,514,516,518,520,522,524,526,529],{"class":29,"line":30},[27,503,49],{"class":48},[27,505,68],{"class":44},[27,507,71],{"class":40},[27,509,74],{"class":44},[27,511,144],{"class":77},[27,513,81],{"class":44},[27,515,84],{"class":55},[27,517,151],{"class":44},[27,519,154],{"class":48},[27,521,52],{"class":44},[27,523,56],{"class":55},[27,525,92],{"class":44},[27,527,528],{"class":95},"\u002F* keep this cheap *\u002F",[27,530,99],{"class":44},[13,532,533],{},"This runs inside the tick, awaited, so anything slow here is added to every tick's\nlatency. For a continuous cognet at 125Hz that cost lands 125 times a second. Treat it as\na hot path or leave it empty.",[226,535,537,540],{"id":536},"shutdown-checkpoint",[24,538,539],{},"shutdown"," — checkpoint",[13,542,543],{},"Fires once at unload.",[17,545,547],{"className":19,"code":546,"language":21,"meta":22,"style":22},"hooks.on(\"shutdown\", async () => {\n    await kernel.store.set(\"checkpoint\", { seq: state.seq, savedAt: Date.now() })\n})\n",[24,548,549,571,620],{"__ignoreMap":22},[27,550,551,553,555,557,559,561,563,565,567,569],{"class":29,"line":30},[27,552,49],{"class":48},[27,554,68],{"class":44},[27,556,71],{"class":40},[27,558,74],{"class":44},[27,560,179],{"class":77},[27,562,81],{"class":44},[27,564,84],{"class":55},[27,566,87],{"class":44},[27,568,56],{"class":55},[27,570,59],{"class":44},[27,572,573,576,578,580,582,584,587,589,591,594,597,600,602,604,606,609,612,614,617],{"class":29,"line":62},[27,574,575],{"class":33},"    await",[27,577,319],{"class":48},[27,579,68],{"class":44},[27,581,324],{"class":48},[27,583,68],{"class":44},[27,585,586],{"class":40},"set",[27,588,74],{"class":44},[27,590,334],{"class":77},[27,592,593],{"class":44},", { ",[27,595,596],{"class":48},"seq:",[27,598,599],{"class":48}," state",[27,601,68],{"class":44},[27,603,404],{"class":48},[27,605,81],{"class":44},[27,607,608],{"class":48},"savedAt:",[27,610,611],{"class":48}," Date",[27,613,68],{"class":44},[27,615,616],{"class":40},"now",[27,618,619],{"class":44},"() })\n",[27,621,622],{"class":29,"line":102},[27,623,200],{"class":44},[13,625,626,627,630,631,634],{},"Note what ",[24,628,629],{},"zero"," does ",[209,632,633],{},"not"," do here: it doesn't flush the conversation, persist entries,\nor save the model. Durable episodic writes already happened through the kernel at the\nmoment they mattered. The only thing worth persisting from RAM is a cursor — and even\nthat is an optimization, not memory.",[13,636,637,643,644,647],{},[236,638,639,640,642],{},"A cognet must never depend on ",[24,641,539],{}," running."," It won't on ",[24,645,646],{},"kill -9",", and a design\nthat needs it is a design that can't survive power loss. If losing what this hook would\nhave saved is a problem, it belonged in the log.",[226,649,651],{"id":650},"multiple-plugins","Multiple plugins",[13,653,654,655,657],{},"Every file in ",[24,656,206],{}," is loaded, and each can register any of the four hooks. Handlers\nfor the same hook run in registration order, awaited to completion.",[17,659,663],{"className":660,"code":661,"language":662,"meta":22,"style":22},"language-bash shiki shiki-themes dark-plus","plugins\u002F\n├── setup.ts       # boot hydration, shutdown checkpoint\n└── devtools.ts    # extra telemetry while developing\n","bash",[24,664,665,670,681],{"__ignoreMap":22},[27,666,667],{"class":29,"line":30},[27,668,669],{"class":40},"plugins\u002F\n",[27,671,672,675,678],{"class":29,"line":62},[27,673,674],{"class":40},"├──",[27,676,677],{"class":77}," setup.ts",[27,679,680],{"class":95},"       # boot hydration, shutdown checkpoint\n",[27,682,683,686,689],{"class":29,"line":102},[27,684,685],{"class":40},"└──",[27,687,688],{"class":77}," devtools.ts",[27,690,691],{"class":95},"    # extra telemetry while developing\n",[13,693,694],{},"Splitting by concern is fine. Just keep every one of them plumbing.",[696,697,698],"style",{},"html pre.shiki code .sYbnZ, html code.shiki .sYbnZ{--shiki-default:#C586C0}html pre.shiki code .sCudf, html code.shiki .sCudf{--shiki-default:#DCDCAA}html pre.shiki code .sTNBD, html code.shiki .sTNBD{--shiki-default:#D4D4D4}html pre.shiki code .s3F5K, html code.shiki .s3F5K{--shiki-default:#9CDCFE}html pre.shiki code .scz_3, html code.shiki .scz_3{--shiki-default:#569CD6}html pre.shiki code .sKc5r, html code.shiki .sKc5r{--shiki-default:#CE9178}html pre.shiki code .sOLPB, html code.shiki .sOLPB{--shiki-default:#6A9955}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s9McN, html code.shiki .s9McN{--shiki-default:#4FC1FF}",{"title":22,"searchDepth":62,"depth":62,"links":700},[701,702,704,706,708,710],{"id":228,"depth":62,"text":229},{"id":251,"depth":62,"text":703},"boot — hydrate",{"id":475,"depth":62,"text":705},"wake — per episode",{"id":488,"depth":62,"text":707},"tick — the hot path",{"id":536,"depth":62,"text":709},"shutdown — checkpoint",{"id":650,"depth":62,"text":651},"Lifecycle hooks — boot, wake, tick, shutdown. Plumbing only.","md",{},"\u002Fdocs\u002Fv2\u002Fcognets\u002Ffolder\u002Fplugins",{"title":5,"description":711},"docs\u002Fv2\u002Fcognets\u002Ffolder\u002Fplugins","t2y_v25gzAI3ApcE6Ln_NSSZL3yx_zIbtr1X8HhRiFk",1785156432133]