[{"data":1,"prerenderedAt":1007},["ShallowReactive",2],{"navigation":3,"\u002Freference\u002Fai-chat":189,"\u002Freference\u002Fai-chat-surround":1002},[4,23,40,51,74,116,157,177],{"title":5,"path":6,"stem":7,"children":8,"icon":22},"Get Started","\u002Fget-started","1.get-started\u002F1.index",[9,12,17],{"title":10,"path":6,"stem":7,"icon":11},"Introduction","i-lucide-house",{"title":13,"path":14,"stem":15,"icon":16},"Prerequisites","\u002Fget-started\u002Fprerequisites","1.get-started\u002F2.prerequisites","i-lucide-list-checks",{"title":18,"path":19,"stem":20,"icon":21},"Installation","\u002Fget-started\u002Finstallation","1.get-started\u002F3.installation","i-lucide-settings","i-lucide-rocket",{"title":24,"icon":25,"path":26,"stem":27,"children":28,"page":39},"Develop","i-lucide-code","\u002Fdevelop","2.develop",[29,34],{"title":30,"path":31,"stem":32,"icon":33},"Version Control","\u002Fdevelop\u002Fversion-control","2.develop\u002F1.version-control","i-lucide-git-branch",{"title":35,"path":36,"stem":37,"icon":38},"Claude Code","\u002Fdevelop\u002Fclaude-code","2.develop\u002F2.claude-code","i-lucide-sparkles",false,{"title":41,"icon":42,"path":43,"stem":44,"children":45,"page":39},"Launch","i-lucide-globe","\u002Flaunch","3.launch",[46],{"title":47,"path":48,"stem":49,"icon":50},"Cloudflare","\u002Flaunch\u002Fcloudflare","3.launch\u002F1.cloudflare","i-lucide-cloud-upload",{"title":52,"path":53,"stem":54,"children":55,"icon":73},"Plugins","\u002Fplugins","4.plugins\u002F1.index",[56,58,63,68],{"title":52,"path":53,"stem":54,"icon":57},"i-lucide-list",{"title":59,"path":60,"stem":61,"icon":62},"Public API","\u002Fplugins\u002Fapi-keys","4.plugins\u002F2.api-keys","i-lucide-key",{"title":64,"path":65,"stem":66,"icon":67},"Cron Jobs","\u002Fplugins\u002Fcron-jobs","4.plugins\u002F4.cron-jobs","i-lucide-clock",{"title":69,"path":70,"stem":71,"icon":72},"Rate Limiting","\u002Fplugins\u002Frate-limiting","4.plugins\u002F5.rate-limiting","i-lucide-gauge","i-lucide-puzzle",{"title":75,"path":76,"stem":77,"children":78,"icon":115},"Examples","\u002Fexamples","5.examples\u002F1.index",[79,80,85,90,95,100,105,110],{"title":75,"path":76,"stem":77,"icon":57},{"title":81,"path":82,"stem":83,"icon":84},"Job Management","\u002Fexamples\u002Fjob-management","5.examples\u002F2.job-management","i-lucide-briefcase",{"title":86,"path":87,"stem":88,"icon":89},"Kanban \u002F To-Do List","\u002Fexamples\u002Fkanban-todo","5.examples\u002F3.kanban-todo","i-lucide-kanban",{"title":91,"path":92,"stem":93,"icon":94},"Inventory Management","\u002Fexamples\u002Finventory-management","5.examples\u002F4.inventory-management","i-lucide-package",{"title":96,"path":97,"stem":98,"icon":99},"Mini CRM","\u002Fexamples\u002Fmini-crm","5.examples\u002F5.mini-crm","i-lucide-users",{"title":101,"path":102,"stem":103,"icon":104},"Sales Orders & Invoices","\u002Fexamples\u002Fsales-invoices","5.examples\u002F6.sales-invoices","i-lucide-receipt",{"title":106,"path":107,"stem":108,"icon":109},"Calendar & Booking","\u002Fexamples\u002Fcalendar-booking","5.examples\u002F7.calendar-booking","i-lucide-calendar",{"title":111,"path":112,"stem":113,"icon":114},"Support Tickets","\u002Fexamples\u002Fsupport-tickets","5.examples\u002F8.support-tickets","i-lucide-life-buoy","i-lucide-book-open",{"title":117,"icon":118,"path":119,"stem":120,"children":121,"page":39},"Reference","i-lucide-file-text","\u002Freference","6.reference",[122,127,132,137,142,147,152],{"title":123,"path":124,"stem":125,"icon":126},"Architecture","\u002Freference\u002Farchitecture","6.reference\u002F1.architecture","i-lucide-layers",{"title":128,"path":129,"stem":130,"icon":131},"Permissions","\u002Freference\u002Fpermissions","6.reference\u002F2.permissions","i-lucide-shield",{"title":133,"path":134,"stem":135,"icon":136},"Invitations","\u002Freference\u002Finvitations","6.reference\u002F3.invitations","i-lucide-mail",{"title":138,"path":139,"stem":140,"icon":141},"Webhooks","\u002Freference\u002Fwebhooks","6.reference\u002F4.webhooks","i-lucide-webhook",{"title":143,"path":144,"stem":145,"icon":146},"AI Chat","\u002Freference\u002Fai-chat","6.reference\u002F5.ai-chat","i-lucide-message-square",{"title":148,"path":149,"stem":150,"icon":151},"Activity Log","\u002Freference\u002Factivity-log","6.reference\u002F6.activity-log","i-lucide-scroll",{"title":153,"path":154,"stem":155,"icon":156},"Manual Setup","\u002Freference\u002Fmanual-setup","6.reference\u002F7.manual-setup","i-lucide-wrench",{"title":158,"icon":159,"path":160,"stem":161,"children":162,"page":39},"Legal","i-lucide-scale","\u002Flegal","7.legal",[163,168,172],{"title":164,"path":165,"stem":166,"icon":167},"License","\u002Flegal\u002Flicense","7.legal\u002F1.license","i-lucide-file-check",{"title":169,"path":170,"stem":171,"icon":118},"Terms and Conditions","\u002Flegal\u002Fterms","7.legal\u002F2.terms",{"title":173,"path":174,"stem":175,"icon":176},"Privacy Policy","\u002Flegal\u002Fprivacy","7.legal\u002F3.privacy","i-lucide-lock",{"title":178,"path":179,"stem":180,"children":181,"icon":183},"Upgrades","\u002Fupgrades","8.upgrades\u002F1.index",[182,184],{"title":178,"path":179,"stem":180,"icon":183},"i-lucide-arrow-up-circle",{"title":185,"path":186,"stem":187,"icon":188},"\u002Fapp\u002F* gated subtree routing","\u002Fupgrades\u002Fapp-subtree-routing","8.upgrades\u002F2.app-subtree-routing","i-lucide-route",{"id":190,"title":143,"body":191,"description":995,"extension":996,"links":997,"meta":998,"navigation":999,"path":144,"seo":1000,"stem":145,"__hash__":1001},"docs\u002F6.reference\u002F5.ai-chat.md",{"type":192,"value":193,"toc":982},"minimark",[194,207,220,225,243,265,274,304,313,353,378,382,385,436,440,443,448,455,556,566,595,601,609,768,775,854,862,865,869,930,934,937,964,978],[195,196,197,198,202,203,206],"p",{},"The template ships with a fully wired AI chat — persistent conversations,\ndatabase queries in natural language, typed write tools, streaming\nresponses, and activity-log attribution. It is enabled when\n",[199,200,201],"code",{},"OPENROUTER_API_KEY"," is set in your ",[199,204,205],{},".env","; without a key, the chat UI is\nhidden and no API routes run.",[195,208,209,210,214,215,219],{},"You do ",[211,212,213],"strong",{},"not"," need to install it via a prompt. What you ",[216,217,218],"em",{},"do"," need to know\nis how to make your own tables readable and writable from the chat.",[221,222,224],"h2",{"id":223},"how-it-works","How it works",[195,226,227,230,231,234,235,238,239,242],{},[211,228,229],{},"Stack"," — Vercel AI SDK (",[199,232,233],{},"ai",", ",[199,236,237],{},"@ai-sdk\u002Fvue",") with the OpenRouter\nprovider (",[199,240,241],{},"@openrouter\u002Fai-sdk-provider","). Switch providers by swapping\none package and one line.",[195,244,245,248,249,252,253,256,257,260,261,264],{},[211,246,247],{},"Storage"," — ",[199,250,251],{},"chats"," (one row per conversation) and ",[199,254,255],{},"chat_messages"," (one\nrow per message, including tool calls and outputs) are team-scoped and\nuser-owned. RLS restricts every row to ",[199,258,259],{},"auth.uid()"," + ",[199,262,263],{},"is_team_member()",".",[195,266,267,248,270,273],{},[211,268,269],{},"Endpoints",[199,271,272],{},"server\u002Fapi\u002Fchats\u002F",":",[275,276,277,284,290],"ul",{},[278,279,280,283],"li",{},[199,281,282],{},"GET \u002Fapi\u002Fchats"," — list the user's chats for the current team",[278,285,286,289],{},[199,287,288],{},"POST \u002Fapi\u002Fchats"," — create a new chat",[278,291,292,295,296,299,300,303],{},[199,293,294],{},"POST \u002Fapi\u002Fchats\u002F[id]"," — stream a response for a message; the endpoint\nroutes writes through ",[199,297,298],{},"createAuditedClient({ source: 'chat', sourceRef: id })","\nso every mutation lands in ",[199,301,302],{},"activity_log"," tagged with the chat ID",[195,305,306,248,309,312],{},[211,307,308],{},"Tools",[199,310,311],{},"server\u002Futils\u002Fchat-tools\u002F"," exports:",[275,314,315,328,347],{},[278,316,317,248,320,323,324,327],{},[199,318,319],{},"queryTools(ctx)",[199,321,322],{},"query_database"," (read-only SQL via the sandboxed\n",[199,325,326],{},"chat_reader"," Postgres role)",[278,329,330,333,334,234,337,234,340,343,344],{},[199,331,332],{},"mutationTools(ctx)"," — typed ",[199,335,336],{},"create_*",[199,338,339],{},"update_*",[199,341,342],{},"delete_*"," tools\ngenerated from the tables in ",[199,345,346],{},"tablePermissions",[278,348,349,352],{},[199,350,351],{},"webSearchTools(ctx)"," — web search tool when enabled",[195,354,355,248,358,361,362,365,366,369,370,373,374,377],{},[211,356,357],{},"Schema introspection",[199,359,360],{},"server\u002Futils\u002FgetDbSchema.ts"," feeds the LLM a\ncompact description of each allowed table: columns and types, CHECK\nconstraints rendered as ",[199,363,364],{},"one of: (...)"," lists, foreign keys as\n",[199,367,368],{},"fk: other_table.id",", and ",[199,371,372],{},"COMMENT ON COLUMN"," text as the free-text hint\nafter the ",[199,375,376],{},"—",". Enum violations and constraint errors are enriched with the\nsame constraint map before being returned to the LLM, so the model can\nself-correct.",[221,379,381],{"id":380},"security-model","Security model",[195,383,384],{},"The LLM never touches the database directly. Enforcement is in three\nplaces:",[386,387,388,396,411],"ol",{},[278,389,390,395],{},[211,391,392,394],{},[199,393,346],{}," gate"," — a table not listed in the map is invisible\nto the chat tools. Adding a table to the LLM's surface is an explicit,\nper-table, per-CRUD decision (see below).",[278,397,398,403,404,406,407,410],{},[211,399,400,402],{},[199,401,326],{}," Postgres role"," — every LLM-generated SELECT runs as\n",[199,405,326],{},", a nologin role that only has SELECT on the tables granted\nto it. Parallel RLS policies scoped ",[199,408,409],{},"TO chat_reader"," mirror the team\nboundaries. The LLM cannot see another team's data even if it crafts a\nquery claiming it can.",[278,412,413,416,417,420,421,424,425,428,429,420,431,424,433,435],{},[211,414,415],{},"Typed write tools"," — the LLM cannot execute ",[199,418,419],{},"INSERT"," \u002F ",[199,422,423],{},"UPDATE"," \u002F\n",[199,426,427],{},"DELETE"," as raw SQL. Writes go through ",[199,430,336],{},[199,432,339],{},[199,434,342],{}," tools with Zod-validated inputs, scoped to the current\nteam, enforcing the same per-user permission check as the API routes.",[221,437,439],{"id":438},"adding-a-new-table-to-chat","Adding a new table to chat",[195,441,442],{},"Do this once per table you want the assistant to read or write. Everything\nis in two files plus one migration.",[444,445,447],"h3",{"id":446},"_1-migration-make-the-table-chat-friendly","1. Migration — make the table chat-friendly",[195,449,450,451,454],{},"Harden the schema so the schema-to-prompt introspection gives the LLM the\nallowed values and intent of each column. ",[199,452,453],{},"getDbSchema"," reads CHECK\nconstraints and column comments directly — whatever you put here is what\nthe model sees.",[456,457,462],"pre",{"className":458,"code":459,"language":460,"meta":461,"style":461},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","-- CHECK constraints for enum-like columns and format rules.\n-- Single-column IN (...) checks are parsed into allowed-value lists in\n-- the prompt. Compound CHECKs fall back to the raw definition.\nalter table tasks\n  add constraint tasks_status_check   check (status in ('open','in_progress','done')),\n  add constraint tasks_priority_check check (priority in ('low','normal','high'));\n\n-- COMMENT ON COLUMN — one short technical sentence per non-obvious column.\n-- Mention format rules the DB does not enforce (the LLM obeys these).\ncomment on column tasks.status   is 'Current state. Moves forward only: open → in_progress → done.';\ncomment on column tasks.priority is 'Task urgency. Defaults to normal.';\ncomment on column tasks.due_date is 'Target completion date. Nullable.';\n\n-- Activity log opt-in (see Activity Log reference).\nselect enable_activity_log('tasks');\n","sql","",[199,463,464,472,478,484,490,496,502,509,515,521,527,533,539,544,550],{"__ignoreMap":461},[465,466,469],"span",{"class":467,"line":468},"line",1,[465,470,471],{},"-- CHECK constraints for enum-like columns and format rules.\n",[465,473,475],{"class":467,"line":474},2,[465,476,477],{},"-- Single-column IN (...) checks are parsed into allowed-value lists in\n",[465,479,481],{"class":467,"line":480},3,[465,482,483],{},"-- the prompt. Compound CHECKs fall back to the raw definition.\n",[465,485,487],{"class":467,"line":486},4,[465,488,489],{},"alter table tasks\n",[465,491,493],{"class":467,"line":492},5,[465,494,495],{},"  add constraint tasks_status_check   check (status in ('open','in_progress','done')),\n",[465,497,499],{"class":467,"line":498},6,[465,500,501],{},"  add constraint tasks_priority_check check (priority in ('low','normal','high'));\n",[465,503,505],{"class":467,"line":504},7,[465,506,508],{"emptyLinePlaceholder":507},true,"\n",[465,510,512],{"class":467,"line":511},8,[465,513,514],{},"-- COMMENT ON COLUMN — one short technical sentence per non-obvious column.\n",[465,516,518],{"class":467,"line":517},9,[465,519,520],{},"-- Mention format rules the DB does not enforce (the LLM obeys these).\n",[465,522,524],{"class":467,"line":523},10,[465,525,526],{},"comment on column tasks.status   is 'Current state. Moves forward only: open → in_progress → done.';\n",[465,528,530],{"class":467,"line":529},11,[465,531,532],{},"comment on column tasks.priority is 'Task urgency. Defaults to normal.';\n",[465,534,536],{"class":467,"line":535},12,[465,537,538],{},"comment on column tasks.due_date is 'Target completion date. Nullable.';\n",[465,540,542],{"class":467,"line":541},13,[465,543,508],{"emptyLinePlaceholder":507},[465,545,547],{"class":467,"line":546},14,[465,548,549],{},"-- Activity log opt-in (see Activity Log reference).\n",[465,551,553],{"class":467,"line":552},15,[465,554,555],{},"select enable_activity_log('tasks');\n",[195,557,558,559,562,563,565],{},"If the table needs to be ",[211,560,561],{},"readable"," from chat, grant ",[199,564,326],{}," SELECT\naccess and add a parallel RLS policy:",[456,567,569],{"className":458,"code":568,"language":460,"meta":461,"style":461},"grant select on tasks to chat_reader;\n\ncreate policy \"tasks_select_chat\" on tasks\n  for select to chat_reader\n  using (team_id = current_chat_team());\n",[199,570,571,576,580,585,590],{"__ignoreMap":461},[465,572,573],{"class":467,"line":468},[465,574,575],{},"grant select on tasks to chat_reader;\n",[465,577,578],{"class":467,"line":474},[465,579,508],{"emptyLinePlaceholder":507},[465,581,582],{"class":467,"line":480},[465,583,584],{},"create policy \"tasks_select_chat\" on tasks\n",[465,586,587],{"class":467,"line":486},[465,588,589],{},"  for select to chat_reader\n",[465,591,592],{"class":467,"line":492},[465,593,594],{},"  using (team_id = current_chat_team());\n",[195,596,597,598,600],{},"Writes run through typed tools using the service role client, so no\n",[199,599,409],{}," write policies are needed.",[444,602,604,605,608],{"id":603},"_2-sharedpermissionsts-register-the-table","2. ",[199,606,607],{},"shared\u002Fpermissions.ts"," — register the table",[456,610,614],{"className":611,"code":612,"language":613,"meta":461,"style":461},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","export const tablePermissions = {\n  \u002F\u002F ...\n  tasks: {\n    view:   \"tasks.view\",\n    create: \"tasks.create\",\n    update: \"tasks.update\",\n    delete: \"tasks.delete\",\n  },\n} as const satisfies Record\u003Cstring, Record\u003CCrudAction, Permission>>;\n","ts",[199,615,616,637,643,653,673,690,706,722,727],{"__ignoreMap":461},[465,617,618,622,626,630,634],{"class":467,"line":468},[465,619,621],{"class":620},"s7zQu","export",[465,623,625],{"class":624},"spNyl"," const",[465,627,629],{"class":628},"sTEyZ"," tablePermissions ",[465,631,633],{"class":632},"sMK4o","=",[465,635,636],{"class":632}," {\n",[465,638,639],{"class":467,"line":474},[465,640,642],{"class":641},"sHwdD","  \u002F\u002F ...\n",[465,644,645,649,651],{"class":467,"line":480},[465,646,648],{"class":647},"swJcz","  tasks",[465,650,273],{"class":632},[465,652,636],{"class":632},[465,654,655,658,660,663,667,670],{"class":467,"line":486},[465,656,657],{"class":647},"    view",[465,659,273],{"class":632},[465,661,662],{"class":632},"   \"",[465,664,666],{"class":665},"sfazB","tasks.view",[465,668,669],{"class":632},"\"",[465,671,672],{"class":632},",\n",[465,674,675,678,680,683,686,688],{"class":467,"line":492},[465,676,677],{"class":647},"    create",[465,679,273],{"class":632},[465,681,682],{"class":632}," \"",[465,684,685],{"class":665},"tasks.create",[465,687,669],{"class":632},[465,689,672],{"class":632},[465,691,692,695,697,699,702,704],{"class":467,"line":498},[465,693,694],{"class":647},"    update",[465,696,273],{"class":632},[465,698,682],{"class":632},[465,700,701],{"class":665},"tasks.update",[465,703,669],{"class":632},[465,705,672],{"class":632},[465,707,708,711,713,715,718,720],{"class":467,"line":504},[465,709,710],{"class":647},"    delete",[465,712,273],{"class":632},[465,714,682],{"class":632},[465,716,717],{"class":665},"tasks.delete",[465,719,669],{"class":632},[465,721,672],{"class":632},[465,723,724],{"class":467,"line":511},[465,725,726],{"class":632},"  },\n",[465,728,729,732,735,738,741,744,747,750,753,755,757,760,762,765],{"class":467,"line":517},[465,730,731],{"class":632},"}",[465,733,734],{"class":620}," as",[465,736,625],{"class":737},"sBMFI",[465,739,740],{"class":620}," satisfies",[465,742,743],{"class":737}," Record",[465,745,746],{"class":632},"\u003C",[465,748,749],{"class":737},"string",[465,751,752],{"class":632},",",[465,754,743],{"class":737},[465,756,746],{"class":632},[465,758,759],{"class":737},"CrudAction",[465,761,752],{"class":632},[465,763,764],{"class":737}," Permission",[465,766,767],{"class":632},">>;\n",[195,769,770,771,774],{},"Read-only tables point their write actions at ",[199,772,773],{},"readonly.write"," (empty role\nset):",[456,776,778],{"className":611,"code":777,"language":613,"meta":461,"style":461},"activity_log: {\n  view:   \"activity.view\",\n  create: \"readonly.write\",\n  update: \"readonly.write\",\n  delete: \"readonly.write\",\n},\n",[199,779,780,788,804,819,834,849],{"__ignoreMap":461},[465,781,782,784,786],{"class":467,"line":468},[465,783,302],{"class":737},[465,785,273],{"class":632},[465,787,636],{"class":632},[465,789,790,793,795,797,800,802],{"class":467,"line":474},[465,791,792],{"class":737},"  view",[465,794,273],{"class":632},[465,796,662],{"class":632},[465,798,799],{"class":665},"activity.view",[465,801,669],{"class":632},[465,803,672],{"class":632},[465,805,806,809,811,813,815,817],{"class":467,"line":480},[465,807,808],{"class":737},"  create",[465,810,273],{"class":632},[465,812,682],{"class":632},[465,814,773],{"class":665},[465,816,669],{"class":632},[465,818,672],{"class":632},[465,820,821,824,826,828,830,832],{"class":467,"line":486},[465,822,823],{"class":737},"  update",[465,825,273],{"class":632},[465,827,682],{"class":632},[465,829,773],{"class":665},[465,831,669],{"class":632},[465,833,672],{"class":632},[465,835,836,839,841,843,845,847],{"class":467,"line":492},[465,837,838],{"class":737},"  delete",[465,840,273],{"class":632},[465,842,682],{"class":632},[465,844,773],{"class":665},[465,846,669],{"class":632},[465,848,672],{"class":632},[465,850,851],{"class":467,"line":498},[465,852,853],{"class":632},"},\n",[444,855,857,858,861],{"id":856},"_3-serverutilschat-toolsmutationsts-optional-custom-write-tool","3. ",[199,859,860],{},"server\u002Futils\u002Fchat-tools\u002Fmutations.ts"," — (optional) custom write tool",[195,863,864],{},"The generic create\u002Fupdate\u002Fdelete tools cover most tables. Add a custom\ntool only when the resource needs unusual validation, multi-step\norchestration, or side-effects that differ from a raw upsert.",[221,866,868],{"id":867},"configuration","Configuration",[275,870,871,886,900],{},[278,872,873,877,878,885],{},[211,874,875],{},[199,876,201],{}," — required. Gets you access to every model on\nOpenRouter through one key. Get one at ",[879,880,884],"a",{"href":881,"rel":882},"https:\u002F\u002Fopenrouter.ai",[883],"nofollow","openrouter.ai",".\nLeave blank to disable the chat and hide its UI.",[278,887,888,891,892,895,896,899],{},[211,889,890],{},"Model"," — set in ",[199,893,894],{},"server\u002Fapi\u002Fchats\u002F[id].post.ts"," via\n",[199,897,898],{},"openrouter(\"anthropic\u002Fclaude-sonnet-4-6\")",". Swap to any OpenRouter model\nby changing the string.",[278,901,902,905,906,420,909,424,912,915,916,424,919,420,922,925,926,929],{},[211,903,904],{},"Switching providers"," — install ",[199,907,908],{},"@ai-sdk\u002Fanthropic",[199,910,911],{},"@ai-sdk\u002Fopenai",[199,913,914],{},"@ai-sdk\u002Fgoogle",", use ",[199,917,918],{},"anthropic(\"claude-sonnet-4-6\")",[199,920,921],{},"openai(\"gpt-4o\")",[199,923,924],{},"google(\"gemini-2.5-pro\")",", set the matching\n",[199,927,928],{},"*_API_KEY",". Everything else stays the same.",[221,931,933],{"id":932},"testing","Testing",[195,935,936],{},"Once you've added a table, try questions that exercise both surfaces:",[275,938,939,945,951],{},[278,940,941,944],{},[211,942,943],{},"Read"," — \"How many open tasks do we have?\" \u002F \"Show me the latest 5\ntasks assigned to Sarah\"",[278,946,947,950],{},[211,948,949],{},"Write"," — \"Create a task called 'Review Q2 budget', priority high,\ndue next Friday\"",[278,952,953,956,957,960,961,963],{},[211,954,955],{},"Constraint feedback"," — ask it to create a task with a bad ",[199,958,959],{},"status","\nvalue. It should see the ",[199,962,364],{}," list in the error and retry.",[195,965,966,967,970,971,974,975,264],{},"Every write shows up at ",[199,968,969],{},"\u002Fapp\u002Factivity"," tagged with ",[199,972,973],{},"source='chat'"," and the\nchat ID in ",[199,976,977],{},"source_ref",[979,980,981],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}",{"title":461,"searchDepth":468,"depth":474,"links":983},[984,985,986,993,994],{"id":223,"depth":474,"text":224},{"id":380,"depth":474,"text":381},{"id":438,"depth":474,"text":439,"children":987},[988,989,991],{"id":446,"depth":480,"text":447},{"id":603,"depth":480,"text":990},"2. shared\u002Fpermissions.ts — register the table",{"id":856,"depth":480,"text":992},"3. server\u002Futils\u002Fchat-tools\u002Fmutations.ts — (optional) custom write tool",{"id":867,"depth":474,"text":868},{"id":932,"depth":474,"text":933},"How the baked-in AI assistant works, and how to make new tables available to it.","md",null,{},{"icon":146},{"title":143,"description":995},"rq0tVFicbGztK3zfMIltfg82fBlAEfmTO7GtnqhGgWY",[1003,1005],{"title":138,"path":139,"stem":140,"description":1004,"icon":141,"children":-1},"Fire-and-forget event dispatch for invites, member changes, team updates, and any mutation you want to expose.",{"title":148,"path":149,"stem":150,"description":1006,"icon":151,"children":-1},"Trigger-driven audit of every mutation on opted-in tables.",1777092171555]