[{"data":1,"prerenderedAt":1054},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fv2\u002Fconcepts\u002Fevents-and-inbox":3},{"id":4,"title":5,"body":6,"description":16,"extension":1048,"meta":1049,"navigation":191,"path":1050,"seo":1051,"stem":1052,"__hash__":1053},"docs\u002Fdocs\u002Fv2\u002Fconcepts\u002Fevents-and-inbox.md","Routes & Hooks",{"type":7,"value":8,"toc":1041},"minimark",[9,13,17,20,25,32,115,118,418,421,425,428,478,624,627,631,638,906,910,913,973,979,983,986,1027,1030,1037],[10,11,5],"h1",{"id":12},"routes-hooks",[14,15,16],"p",{},"Scripts handle outbound work — you invoke them, they run, they finish. Routes and hooks\nhandle inbound work — the outside world triggers your agent.",[14,18,19],{},"The pattern is always the same: something external happens, a route receives it, the agent\nis invoked with context about what happened.",[21,22,24],"h2",{"id":23},"routes","Routes",[14,26,27,31],{},[28,29,30],"code",{},"server\u002Fapi\u002F"," is the complete inbound surface. File-based routing maps filenames to HTTP\npaths and methods.",[33,34,39],"pre",{"className":35,"code":36,"language":37,"meta":38,"style":38},"language-bash shiki shiki-themes dark-plus","server\u002Fapi\u002F\n├── webhooks\u002F\n│   └── github.post.ts   → POST \u002Fapi\u002Fwebhooks\u002Fgithub\n├── chat.post.ts         → POST \u002Fapi\u002Fchat\n└── status.get.ts        → GET \u002Fapi\u002Fstatus\n","bash","",[28,40,41,50,60,81,97],{"__ignoreMap":38},[42,43,46],"span",{"class":44,"line":45},"line",1,[42,47,49],{"class":48},"sCudf","server\u002Fapi\u002F\n",[42,51,53,56],{"class":44,"line":52},2,[42,54,55],{"class":48},"├──",[42,57,59],{"class":58},"sKc5r"," webhooks\u002F\n",[42,61,63,66,69,72,75,78],{"class":44,"line":62},3,[42,64,65],{"class":48},"│",[42,67,68],{"class":58},"   └──",[42,70,71],{"class":58}," github.post.ts",[42,73,74],{"class":58},"   →",[42,76,77],{"class":58}," POST",[42,79,80],{"class":58}," \u002Fapi\u002Fwebhooks\u002Fgithub\n",[42,82,84,86,89,92,94],{"class":44,"line":83},4,[42,85,55],{"class":48},[42,87,88],{"class":58}," chat.post.ts",[42,90,91],{"class":58},"         →",[42,93,77],{"class":58},[42,95,96],{"class":58}," \u002Fapi\u002Fchat\n",[42,98,100,103,106,109,112],{"class":44,"line":99},5,[42,101,102],{"class":48},"└──",[42,104,105],{"class":58}," status.get.ts",[42,107,108],{"class":58},"        →",[42,110,111],{"class":58}," GET",[42,113,114],{"class":58}," \u002Fapi\u002Fstatus\n",[14,116,117],{},"Routes are standard h3 handlers. They receive a request, do whatever work is needed, and\nreturn a response. Invoking the agent is one option — not automatic.",[33,119,123],{"className":120,"code":121,"language":122,"meta":38,"style":38},"language-ts shiki shiki-themes dark-plus","\u002F\u002F server\u002Fapi\u002Fwebhooks\u002Fgithub.post.ts\nexport default defineEventHandler(async event => {\n    const payload = await readBody(event)\n\n    if (payload.action !== \"opened\") return { ignored: true }\n\n    const prompt = await axon.prompt(\"issue-triage\", {\n        number: payload.issue.number,\n        title: payload.issue.title,\n        body: payload.issue.body,\n    })\n\n    \u002F\u002F fire and forget — respond immediately, agent works asynchronously\n    void axon.request({ prompt, thread: `issue-${payload.issue.number}` })\n\n    return { received: true }\n})\n","ts",[28,124,125,131,161,187,193,234,239,267,288,307,326,332,337,343,392,397,412],{"__ignoreMap":38},[42,126,127],{"class":44,"line":45},[42,128,130],{"class":129},"sOLPB","\u002F\u002F server\u002Fapi\u002Fwebhooks\u002Fgithub.post.ts\n",[42,132,133,137,140,143,147,151,155,158],{"class":44,"line":52},[42,134,136],{"class":135},"sYbnZ","export",[42,138,139],{"class":135}," default",[42,141,142],{"class":48}," defineEventHandler",[42,144,146],{"class":145},"sTNBD","(",[42,148,150],{"class":149},"scz_3","async",[42,152,154],{"class":153},"s3F5K"," event",[42,156,157],{"class":149}," =>",[42,159,160],{"class":145}," {\n",[42,162,163,166,170,173,176,179,181,184],{"class":44,"line":62},[42,164,165],{"class":149},"    const",[42,167,169],{"class":168},"s9McN"," payload",[42,171,172],{"class":145}," = ",[42,174,175],{"class":135},"await",[42,177,178],{"class":48}," readBody",[42,180,146],{"class":145},[42,182,183],{"class":153},"event",[42,185,186],{"class":145},")\n",[42,188,189],{"class":44,"line":83},[42,190,192],{"emptyLinePlaceholder":191},true,"\n",[42,194,195,198,201,204,207,210,213,216,219,222,225,228,231],{"class":44,"line":99},[42,196,197],{"class":135},"    if",[42,199,200],{"class":145}," (",[42,202,203],{"class":153},"payload",[42,205,206],{"class":145},".",[42,208,209],{"class":153},"action",[42,211,212],{"class":145}," !== ",[42,214,215],{"class":58},"\"opened\"",[42,217,218],{"class":145},") ",[42,220,221],{"class":135},"return",[42,223,224],{"class":145}," { ",[42,226,227],{"class":153},"ignored:",[42,229,230],{"class":149}," true",[42,232,233],{"class":145}," }\n",[42,235,237],{"class":44,"line":236},6,[42,238,192],{"emptyLinePlaceholder":191},[42,240,242,244,247,249,251,254,256,259,261,264],{"class":44,"line":241},7,[42,243,165],{"class":149},[42,245,246],{"class":168}," prompt",[42,248,172],{"class":145},[42,250,175],{"class":135},[42,252,253],{"class":153}," axon",[42,255,206],{"class":145},[42,257,258],{"class":48},"prompt",[42,260,146],{"class":145},[42,262,263],{"class":58},"\"issue-triage\"",[42,265,266],{"class":145},", {\n",[42,268,270,273,275,277,280,282,285],{"class":44,"line":269},8,[42,271,272],{"class":153},"        number:",[42,274,169],{"class":153},[42,276,206],{"class":145},[42,278,279],{"class":153},"issue",[42,281,206],{"class":145},[42,283,284],{"class":153},"number",[42,286,287],{"class":145},",\n",[42,289,291,294,296,298,300,302,305],{"class":44,"line":290},9,[42,292,293],{"class":153},"        title:",[42,295,169],{"class":153},[42,297,206],{"class":145},[42,299,279],{"class":153},[42,301,206],{"class":145},[42,303,304],{"class":153},"title",[42,306,287],{"class":145},[42,308,310,313,315,317,319,321,324],{"class":44,"line":309},10,[42,311,312],{"class":153},"        body:",[42,314,169],{"class":153},[42,316,206],{"class":145},[42,318,279],{"class":153},[42,320,206],{"class":145},[42,322,323],{"class":153},"body",[42,325,287],{"class":145},[42,327,329],{"class":44,"line":328},11,[42,330,331],{"class":145},"    })\n",[42,333,335],{"class":44,"line":334},12,[42,336,192],{"emptyLinePlaceholder":191},[42,338,340],{"class":44,"line":339},13,[42,341,342],{"class":129},"    \u002F\u002F fire and forget — respond immediately, agent works asynchronously\n",[42,344,346,349,351,353,356,359,361,364,367,370,373,375,377,379,381,383,386,389],{"class":44,"line":345},14,[42,347,348],{"class":149},"    void",[42,350,253],{"class":153},[42,352,206],{"class":145},[42,354,355],{"class":48},"request",[42,357,358],{"class":145},"({ ",[42,360,258],{"class":153},[42,362,363],{"class":145},", ",[42,365,366],{"class":153},"thread:",[42,368,369],{"class":58}," `issue-",[42,371,372],{"class":149},"${",[42,374,203],{"class":153},[42,376,206],{"class":145},[42,378,279],{"class":153},[42,380,206],{"class":145},[42,382,284],{"class":153},[42,384,385],{"class":149},"}",[42,387,388],{"class":58},"`",[42,390,391],{"class":145}," })\n",[42,393,395],{"class":44,"line":394},15,[42,396,192],{"emptyLinePlaceholder":191},[42,398,400,403,405,408,410],{"class":44,"line":399},16,[42,401,402],{"class":135},"    return",[42,404,224],{"class":145},[42,406,407],{"class":153},"received:",[42,409,230],{"class":149},[42,411,233],{"class":145},[42,413,415],{"class":44,"line":414},17,[42,416,417],{"class":145},"})\n",[14,419,420],{},"The agent runs in a named thread keyed to the issue number. Any follow-up call for the\nsame issue continues that conversation.",[21,422,424],{"id":423},"hooks","Hooks",[14,426,427],{},"Hooks decouple event emission from event handling. A module emits a named hook when\nsomething happens. Your code subscribes to that hook in a plugin. The module doesn't know\nwho's listening — it just fires the event.",[33,429,431],{"className":120,"code":430,"language":122,"meta":38,"style":38},"\u002F\u002F @axon\u002Fgithub module — emits a hook when an issue opens\nawait axon.hooks.callHook(\"github:issue.opened\", { number, title, labels, body })\n",[28,432,433,438],{"__ignoreMap":38},[42,434,435],{"class":44,"line":45},[42,436,437],{"class":129},"\u002F\u002F @axon\u002Fgithub module — emits a hook when an issue opens\n",[42,439,440,442,444,446,448,450,453,455,458,461,463,465,467,469,472,474,476],{"class":44,"line":52},[42,441,175],{"class":135},[42,443,253],{"class":153},[42,445,206],{"class":145},[42,447,423],{"class":153},[42,449,206],{"class":145},[42,451,452],{"class":48},"callHook",[42,454,146],{"class":145},[42,456,457],{"class":58},"\"github:issue.opened\"",[42,459,460],{"class":145},", { ",[42,462,284],{"class":153},[42,464,363],{"class":145},[42,466,304],{"class":153},[42,468,363],{"class":145},[42,470,471],{"class":153},"labels",[42,473,363],{"class":145},[42,475,323],{"class":153},[42,477,391],{"class":145},[33,479,481],{"className":120,"code":480,"language":122,"meta":38,"style":38},"\u002F\u002F server\u002Fplugins\u002Ftriage.ts — your agent subscribes\nexport default defineAxonPlugin(async axon => {\n    axon.hooks.hook(\"github:issue.opened\", async ({ number, title, body }) => {\n        const prompt = await axon.prompt(\"issue-triage\", { number, title, body })\n        void axon.request({ prompt, thread: `issue-${number}` })\n    })\n})\n",[28,482,483,488,507,550,585,616,620],{"__ignoreMap":38},[42,484,485],{"class":44,"line":45},[42,486,487],{"class":129},"\u002F\u002F server\u002Fplugins\u002Ftriage.ts — your agent subscribes\n",[42,489,490,492,494,497,499,501,503,505],{"class":44,"line":52},[42,491,136],{"class":135},[42,493,139],{"class":135},[42,495,496],{"class":48}," defineAxonPlugin",[42,498,146],{"class":145},[42,500,150],{"class":149},[42,502,253],{"class":153},[42,504,157],{"class":149},[42,506,160],{"class":145},[42,508,509,512,514,516,518,521,523,525,527,529,532,534,536,538,540,542,545,548],{"class":44,"line":62},[42,510,511],{"class":153},"    axon",[42,513,206],{"class":145},[42,515,423],{"class":153},[42,517,206],{"class":145},[42,519,520],{"class":48},"hook",[42,522,146],{"class":145},[42,524,457],{"class":58},[42,526,363],{"class":145},[42,528,150],{"class":149},[42,530,531],{"class":145}," ({ ",[42,533,284],{"class":153},[42,535,363],{"class":145},[42,537,304],{"class":153},[42,539,363],{"class":145},[42,541,323],{"class":153},[42,543,544],{"class":145}," }) ",[42,546,547],{"class":149},"=>",[42,549,160],{"class":145},[42,551,552,555,557,559,561,563,565,567,569,571,573,575,577,579,581,583],{"class":44,"line":83},[42,553,554],{"class":149},"        const",[42,556,246],{"class":168},[42,558,172],{"class":145},[42,560,175],{"class":135},[42,562,253],{"class":153},[42,564,206],{"class":145},[42,566,258],{"class":48},[42,568,146],{"class":145},[42,570,263],{"class":58},[42,572,460],{"class":145},[42,574,284],{"class":153},[42,576,363],{"class":145},[42,578,304],{"class":153},[42,580,363],{"class":145},[42,582,323],{"class":153},[42,584,391],{"class":145},[42,586,587,590,592,594,596,598,600,602,604,606,608,610,612,614],{"class":44,"line":99},[42,588,589],{"class":149},"        void",[42,591,253],{"class":153},[42,593,206],{"class":145},[42,595,355],{"class":48},[42,597,358],{"class":145},[42,599,258],{"class":153},[42,601,363],{"class":145},[42,603,366],{"class":153},[42,605,369],{"class":58},[42,607,372],{"class":149},[42,609,284],{"class":153},[42,611,385],{"class":149},[42,613,388],{"class":58},[42,615,391],{"class":145},[42,617,618],{"class":44,"line":236},[42,619,331],{"class":145},[42,621,622],{"class":44,"line":241},[42,623,417],{"class":145},[14,625,626],{},"This is how module integrations work. The module ships the webhook route and emits the\nhook. You subscribe in your plugin and decide what the agent does with it.",[21,628,630],{"id":629},"plugins","Plugins",[14,632,633,634,637],{},"Plugins run at boot and have access to the full ",[28,635,636],{},"axon"," API. They're the right place for\nhook subscriptions, event listeners, and any setup that needs to happen once before the\nserver starts handling requests.",[33,639,641],{"className":120,"code":640,"language":122,"meta":38,"style":38},"\u002F\u002F server\u002Fplugins\u002Fsetup.ts\nexport default defineAxonPlugin(async axon => {\n    \u002F\u002F subscribe to module hooks\n    axon.hooks.hook(\"linear:issue.created\", async ({ id, title }) => {\n        const prompt = await axon.prompt(\"triage\", { id, title })\n        void axon.request({ prompt, thread: `linear-${id}` })\n    })\n\n    \u002F\u002F subscribe to platform hooks\n    axon.hooks.hook(\"email:received\", async ({ from, subject, body }) => {\n        const prompt = await axon.prompt(\"email-process\", { from, subject, body })\n        void axon.request({ prompt, thread: `email-${Date.now()}` })\n    })\n})\n",[28,642,643,648,666,671,707,738,769,773,777,782,823,858,898,902],{"__ignoreMap":38},[42,644,645],{"class":44,"line":45},[42,646,647],{"class":129},"\u002F\u002F server\u002Fplugins\u002Fsetup.ts\n",[42,649,650,652,654,656,658,660,662,664],{"class":44,"line":52},[42,651,136],{"class":135},[42,653,139],{"class":135},[42,655,496],{"class":48},[42,657,146],{"class":145},[42,659,150],{"class":149},[42,661,253],{"class":153},[42,663,157],{"class":149},[42,665,160],{"class":145},[42,667,668],{"class":44,"line":62},[42,669,670],{"class":129},"    \u002F\u002F subscribe to module hooks\n",[42,672,673,675,677,679,681,683,685,688,690,692,694,697,699,701,703,705],{"class":44,"line":83},[42,674,511],{"class":153},[42,676,206],{"class":145},[42,678,423],{"class":153},[42,680,206],{"class":145},[42,682,520],{"class":48},[42,684,146],{"class":145},[42,686,687],{"class":58},"\"linear:issue.created\"",[42,689,363],{"class":145},[42,691,150],{"class":149},[42,693,531],{"class":145},[42,695,696],{"class":153},"id",[42,698,363],{"class":145},[42,700,304],{"class":153},[42,702,544],{"class":145},[42,704,547],{"class":149},[42,706,160],{"class":145},[42,708,709,711,713,715,717,719,721,723,725,728,730,732,734,736],{"class":44,"line":99},[42,710,554],{"class":149},[42,712,246],{"class":168},[42,714,172],{"class":145},[42,716,175],{"class":135},[42,718,253],{"class":153},[42,720,206],{"class":145},[42,722,258],{"class":48},[42,724,146],{"class":145},[42,726,727],{"class":58},"\"triage\"",[42,729,460],{"class":145},[42,731,696],{"class":153},[42,733,363],{"class":145},[42,735,304],{"class":153},[42,737,391],{"class":145},[42,739,740,742,744,746,748,750,752,754,756,759,761,763,765,767],{"class":44,"line":236},[42,741,589],{"class":149},[42,743,253],{"class":153},[42,745,206],{"class":145},[42,747,355],{"class":48},[42,749,358],{"class":145},[42,751,258],{"class":153},[42,753,363],{"class":145},[42,755,366],{"class":153},[42,757,758],{"class":58}," `linear-",[42,760,372],{"class":149},[42,762,696],{"class":153},[42,764,385],{"class":149},[42,766,388],{"class":58},[42,768,391],{"class":145},[42,770,771],{"class":44,"line":241},[42,772,331],{"class":145},[42,774,775],{"class":44,"line":269},[42,776,192],{"emptyLinePlaceholder":191},[42,778,779],{"class":44,"line":290},[42,780,781],{"class":129},"    \u002F\u002F subscribe to platform hooks\n",[42,783,784,786,788,790,792,794,796,799,801,803,805,808,810,813,815,817,819,821],{"class":44,"line":309},[42,785,511],{"class":153},[42,787,206],{"class":145},[42,789,423],{"class":153},[42,791,206],{"class":145},[42,793,520],{"class":48},[42,795,146],{"class":145},[42,797,798],{"class":58},"\"email:received\"",[42,800,363],{"class":145},[42,802,150],{"class":149},[42,804,531],{"class":145},[42,806,807],{"class":153},"from",[42,809,363],{"class":145},[42,811,812],{"class":153},"subject",[42,814,363],{"class":145},[42,816,323],{"class":153},[42,818,544],{"class":145},[42,820,547],{"class":149},[42,822,160],{"class":145},[42,824,825,827,829,831,833,835,837,839,841,844,846,848,850,852,854,856],{"class":44,"line":328},[42,826,554],{"class":149},[42,828,246],{"class":168},[42,830,172],{"class":145},[42,832,175],{"class":135},[42,834,253],{"class":153},[42,836,206],{"class":145},[42,838,258],{"class":48},[42,840,146],{"class":145},[42,842,843],{"class":58},"\"email-process\"",[42,845,460],{"class":145},[42,847,807],{"class":153},[42,849,363],{"class":145},[42,851,812],{"class":153},[42,853,363],{"class":145},[42,855,323],{"class":153},[42,857,391],{"class":145},[42,859,860,862,864,866,868,870,872,874,876,879,881,884,886,889,892,894,896],{"class":44,"line":334},[42,861,589],{"class":149},[42,863,253],{"class":153},[42,865,206],{"class":145},[42,867,355],{"class":48},[42,869,358],{"class":145},[42,871,258],{"class":153},[42,873,363],{"class":145},[42,875,366],{"class":153},[42,877,878],{"class":58}," `email-",[42,880,372],{"class":149},[42,882,883],{"class":153},"Date",[42,885,206],{"class":145},[42,887,888],{"class":48},"now",[42,890,891],{"class":145},"()",[42,893,385],{"class":149},[42,895,388],{"class":58},[42,897,391],{"class":145},[42,899,900],{"class":44,"line":339},[42,901,331],{"class":145},[42,903,904],{"class":44,"line":345},[42,905,417],{"class":145},[21,907,909],{"id":908},"platform-hooks","Platform hooks",[14,911,912],{},"These are emitted by the Axon runtime itself — no module required.",[914,915,916,929],"table",{},[917,918,919],"thead",{},[920,921,922,926],"tr",{},[923,924,925],"th",{},"Hook",[923,927,928],{},"When",[930,931,932,943,953,963],"tbody",{},[920,933,934,940],{},[935,936,937],"td",{},[28,938,939],{},"boot",[935,941,942],{},"Agent is starting",[920,944,945,950],{},[935,946,947],{},[28,948,949],{},"shutdown",[935,951,952],{},"Agent is stopping",[920,954,955,960],{},[935,956,957],{},[28,958,959],{},"server:ready",[935,961,962],{},"HTTP server is listening",[920,964,965,970],{},[935,966,967],{},[28,968,969],{},"email:received",[935,971,972],{},"Inbound email arrived",[14,974,975,976,978],{},"Every deployed agent gets its own email address. The ",[28,977,969],{},"\nhook fires automatically. Subscribe to it in a plugin to make your agent respond to email\nwithout installing anything.",[21,980,982],{"id":981},"fire-and-forget","Fire and forget",[14,984,985],{},"When a route needs to acknowledge receipt immediately and let the agent work in the\nbackground, void the invocation and return early:",[33,987,989],{"className":120,"code":988,"language":122,"meta":38,"style":38},"void axon.request({ prompt, thread: \"background-task\" })\nreturn { received: true }\n",[28,990,991,1015],{"__ignoreMap":38},[42,992,993,996,998,1000,1002,1004,1006,1008,1010,1013],{"class":44,"line":45},[42,994,995],{"class":149},"void",[42,997,253],{"class":153},[42,999,206],{"class":145},[42,1001,355],{"class":48},[42,1003,358],{"class":145},[42,1005,258],{"class":153},[42,1007,363],{"class":145},[42,1009,366],{"class":153},[42,1011,1012],{"class":58}," \"background-task\"",[42,1014,391],{"class":145},[42,1016,1017,1019,1021,1023,1025],{"class":44,"line":52},[42,1018,221],{"class":135},[42,1020,224],{"class":145},[42,1022,407],{"class":153},[42,1024,230],{"class":149},[42,1026,233],{"class":145},[14,1028,1029],{},"The route returns before the loop completes. The caller gets an immediate response. The\nagent runs to completion in the background and writes its output to the thread.",[14,1031,1032,1033,1036],{},"Use this for webhooks and any integration where the caller has a short timeout. Don't use\nit when the caller needs the agent's response to construct their own response — use\n",[28,1034,1035],{},"axon.stream()"," and pipe the entries instead.",[1038,1039,1040],"style",{},"html pre.shiki code .sCudf, html code.shiki .sCudf{--shiki-default:#DCDCAA}html pre.shiki code .sKc5r, html code.shiki .sKc5r{--shiki-default:#CE9178}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 .sOLPB, html code.shiki .sOLPB{--shiki-default:#6A9955}html pre.shiki code .sYbnZ, html code.shiki .sYbnZ{--shiki-default:#C586C0}html pre.shiki code .sTNBD, html code.shiki .sTNBD{--shiki-default:#D4D4D4}html pre.shiki code .scz_3, html code.shiki .scz_3{--shiki-default:#569CD6}html pre.shiki code .s3F5K, html code.shiki .s3F5K{--shiki-default:#9CDCFE}html pre.shiki code .s9McN, html code.shiki .s9McN{--shiki-default:#4FC1FF}",{"title":38,"searchDepth":52,"depth":52,"links":1042},[1043,1044,1045,1046,1047],{"id":23,"depth":52,"text":24},{"id":423,"depth":52,"text":424},{"id":629,"depth":52,"text":630},{"id":908,"depth":52,"text":909},{"id":981,"depth":52,"text":982},"md",{},"\u002Fdocs\u002Fv2\u002Fconcepts\u002Fevents-and-inbox",{"title":5,"description":16},"docs\u002Fv2\u002Fconcepts\u002Fevents-and-inbox","vgsuY4dnAGGYb927YikyvUuYMffmQrI5YXLlU747DvA",1785671807723]