[{"data":1,"prerenderedAt":823},["ShallowReactive",2],{"navigation_docs":3,"-introduction":139,"-introduction-surround":820},[4,8,12,16,20,24,28,32,59,63,117,121,135],{"title":5,"path":6,"stem":7},"Introduction","\u002Fintroduction","1.introduction",{"title":9,"path":10,"stem":11},"Memory","\u002Fmemory","10.memory",{"title":13,"path":14,"stem":15},"Customization","\u002Fcustomization","11.customization",{"title":17,"path":18,"stem":19},"Deployment","\u002Fdeployment","12.deployment",{"title":21,"path":22,"stem":23},"Reference","\u002Freference","13.reference",{"title":25,"path":26,"stem":27},"Quickstart","\u002Fquickstart","2.quickstart",{"title":29,"path":30,"stem":31},"Installation","\u002Finstallation","3.installation",{"title":33,"icon":34,"path":35,"stem":36,"children":37,"page":58},"Connectors","i-lucide-cable","\u002Fconnectors","4.connectors",[38,42,46,50,54],{"title":39,"path":40,"stem":41},"Telegram","\u002Fconnectors\u002Ftelegram","4.connectors\u002F1.telegram",{"title":43,"path":44,"stem":45},"Slack","\u002Fconnectors\u002Fslack","4.connectors\u002F2.slack",{"title":47,"path":48,"stem":49},"Email","\u002Fconnectors\u002Femail","4.connectors\u002F3.email",{"title":51,"path":52,"stem":53},"API","\u002Fconnectors\u002Fapi","4.connectors\u002F4.api",{"title":55,"path":56,"stem":57},"Terminal","\u002Fconnectors\u002Fterminal","4.connectors\u002F5.terminal",false,{"title":60,"path":61,"stem":62},"Attachments","\u002Fattachments","5.attachments",{"title":64,"icon":65,"path":66,"stem":67,"children":68,"page":58},"Tools","i-lucide-wrench","\u002Ftools","6.tools",[69,73,77,81,85,89,93,97,101,105,109,113],{"title":70,"path":71,"stem":72},"File Manager","\u002Ftools\u002Ffile-manager","6.tools\u002F1.file-manager",{"title":74,"path":75,"stem":76},"Text-to-Speech","\u002Ftools\u002Ftext-to-speech","6.tools\u002F10.text-to-speech",{"title":78,"path":79,"stem":80},"Confirmations","\u002Ftools\u002Fconfirmations","6.tools\u002F11.confirmations",{"title":82,"path":83,"stem":84},"Adding Custom Tools","\u002Ftools\u002Fadding-custom-tools","6.tools\u002F12.adding-custom-tools",{"title":86,"path":87,"stem":88},"Image Manager","\u002Ftools\u002Fimage-manager","6.tools\u002F2.image-manager",{"title":90,"path":91,"stem":92},"Web Request","\u002Ftools\u002Fweb-request","6.tools\u002F3.web-request",{"title":94,"path":95,"stem":96},"Reminders","\u002Ftools\u002Freminders","6.tools\u002F4.reminders",{"title":98,"path":99,"stem":100},"Heartbeats","\u002Ftools\u002Fheartbeats","6.tools\u002F5.heartbeats",{"title":102,"path":103,"stem":104},"Email Manager","\u002Ftools\u002Femail-manager","6.tools\u002F6.email-manager",{"title":106,"path":107,"stem":108},"Calendar","\u002Ftools\u002Fcalendar","6.tools\u002F7.calendar",{"title":110,"path":111,"stem":112},"Read Database","\u002Ftools\u002Fread-database","6.tools\u002F8.read-database",{"title":114,"path":115,"stem":116},"Headless Browser","\u002Ftools\u002Fbrowser","6.tools\u002F9.browser",{"title":118,"path":119,"stem":120},"Tinker","\u002Ftinker","7.tinker",{"title":122,"icon":123,"path":124,"stem":125,"children":126,"page":58},"Skills","i-lucide-sparkles","\u002Fskills","8.skills",[127,131],{"title":128,"path":129,"stem":130},"Overview","\u002Fskills\u002Foverview","8.skills\u002F1.overview",{"title":132,"path":133,"stem":134},"Adding Custom Skills","\u002Fskills\u002Fadding-custom-skills","8.skills\u002F2.adding-custom-skills",{"title":136,"path":137,"stem":138},"Personas","\u002Fpersonas","9.personas",{"id":140,"title":5,"body":141,"description":813,"extension":814,"links":815,"meta":816,"navigation":817,"path":6,"seo":818,"stem":7,"__hash__":819},"docs\u002F1.introduction.md",{"type":142,"value":143,"toc":795},"minimark",[144,149,158,161,177,191,195,202,209,216,223,233,237,240,244,266,269,281,284,297,300,312,315,327,331,349,353,464,468,471,481,484,554,560,564,571,724,727,758,762,765,792],[145,146,148],"h2",{"id":147},"what-is-laraclaw","What Is Laraclaw",[150,151,152,153,157],"p",{},"You've built a Laravel app and you'd love to talk to it. Not click around it — ",[154,155,156],"em",{},"talk"," to it. You want to ask \"any new orders?\" from Telegram, drop a PDF into a Slack DM and have it filed, or receive a report via email every morning.",[150,159,160],{},"That's Laraclaw.",[150,162,163,164,168,169,172,173,176],{},"Laraclaw is a Laravel package that turns your application into an AI assistant you can reach from five surfaces: ",[165,166,167],"strong",{},"Telegram, Slack, Email,"," an ",[165,170,171],{},"HTTP API,"," and the ",[165,174,175],{},"terminal."," The agent reads your messages, calls tools (read a file, query the database, schedule a reminder, send an email), and replies through the same channel you wrote in.",[150,178,179,180,190],{},"It's built on top of ",[181,182,186],"a",{"href":183,"rel":184},"https:\u002F\u002Fgithub.com\u002Flaravel\u002Fai",[185],"nofollow",[187,188,189],"code",{},"laravel\u002Fai",", so the actual model — Anthropic, OpenAI, Mistral, Ollama, anything else — is whatever you've configured. Laraclaw handles the surrounding pieces: routing messages, persisting conversations, executing tools, scheduling reminders, retrieving past context, and keeping the whole thing safe.",[145,192,194],{"id":193},"the-one-owner-model","The One-Owner Model",[150,196,197,198,201],{},"Here's the most important thing to understand up front: ",[165,199,200],{},"Laraclaw is single-user",".",[150,203,204,205,208],{},"Every install has exactly one owner — one user, identified by ",[187,206,207],{},"LARACLAW_ADMIN_USER_ID",". The owner is the only identity the agent ever speaks for. There is no multi-tenant mode, no per-user data scoping, no role system. If the agent reads the calendar, it's the owner's calendar. If it sends an email, it's from the owner's mailbox. If it runs Tinker, it's with the owner's full privileges.",[150,210,211,212,215],{},"Now, you might be wondering: ",[154,213,214],{},"can other people still talk to it?"," Yes! The owner can drop the bot into a shared Slack channel, a Telegram group, or a server's terminal — anyone in those rooms can prompt the agent and the agent will reply. But every tool call still runs as the owner.",[150,217,218,219,222],{},"DM connectors (Telegram DM, Slack DM, Email) are stricter: they only respond to addresses registered in the ",[187,220,221],{},"laraclaw_accounts"," table, all of which point at the owner. Any other sender is silently dropped.",[224,225,226],"blockquote",{},[150,227,228,232],{},[229,230,231],"span",{},"!IMPORTANT","\nIf you need a multi-tenant assistant where every user has their own data scope, Laraclaw is not the right fit. The whole package is designed around \"one owner, one trust boundary.\"",[145,234,236],{"id":235},"the-building-blocks","The Building Blocks",[150,238,239],{},"Laraclaw has six terms that show up over and over. They overlap a little in plain English, so let's pin them down before going further.",[241,242,33],"h3",{"id":243},"connectors",[150,245,246,247,250,251,253,254,253,256,258,259,262,263,265],{},"A ",[165,248,249],{},"connector"," is an inbound\u002Foutbound transport. Each one knows how to receive a message (a webhook, an IMAP poll, a CLI prompt) and how to send a reply back the same way. We ship five: ",[181,252,39],{"href":40},", ",[181,255,43],{"href":44},[181,257,47],{"href":48},", the ",[181,260,261],{"href":52},"HTTP API",", and the ",[181,264,55],{"href":56},". Enable the ones you need; the rest stay dormant.",[241,267,64],{"id":268},"tools",[150,270,246,271,274,275,278,279,201],{},[165,272,273],{},"tool"," is a function the agent can call mid-turn. Tools are how the agent does ",[154,276,277],{},"anything"," beyond producing text — read a file, schedule a reminder, send an email, query the database. Laraclaw ships a fixed set of built-in tools and lets you add your own. Browse them under ",[181,280,64],{"href":71},[241,282,118],{"id":283},"tinker",[150,285,286,288,289,292,293,296],{},[181,287,118],{"href":119}," is a tool with unrestricted access to your application: arbitrary PHP via ",[187,290,291],{},"php artisan tinker --execute",", plus shell access via ",[187,294,295],{},"Process::run",". It lives in its own page because it's disabled by default and warrants a separate trust decision. If you turn it on, the agent can execute any code your PHP user can.",[241,298,122],{"id":299},"skills",[150,301,246,302,305,306,309,310,201],{},[165,303,304],{},"skill"," is a Markdown file the agent reads on demand to follow a procedure. Think of it as ",[154,307,308],{},"guidance, not code",": it tells the model \"when you're asked to write release notes, structure the output like this.\" The agent decides which skill applies; Laraclaw just makes them discoverable. See ",[181,311,122],{"href":129},[241,313,136],{"id":314},"personas",[150,316,246,317,320,321,324,325,201],{},[165,318,319],{},"persona"," is a Markdown file appended to the system prompt. Personas change ",[154,322,323],{},"how the agent talks"," — its tone, focus, and conventions — without touching its capabilities. One thread can have one active persona at a time. See ",[181,326,136],{"href":137},[241,328,330],{"id":329},"commands","Commands",[150,332,246,333,336,337,340,341,344,345,201],{},[165,334,335],{},"command"," is a deterministic shortcut that runs ",[154,338,339],{},"before"," the agent loop and never reaches the model. The built-in ",[187,342,343],{},"!new"," command resets the current conversation. Commands are how you wire fast, free, predictable shortcuts for things you don't want the model second-guessing. See ",[181,346,348],{"href":347},"\u002Fcustomization#custom-commands","Custom Commands",[241,350,352],{"id":351},"quick-comparison","Quick Comparison",[354,355,356,375],"table",{},[357,358,359],"thead",{},[360,361,362,366,369,372],"tr",{},[363,364,365],"th",{},"Term",[363,367,368],{},"Lives where",[363,370,371],{},"Run by",[363,373,374],{},"When to use",[376,377,378,393,407,419,434,450],"tbody",{},[360,379,380,384,387,390],{},[381,382,383],"td",{},"Connector",[381,385,386],{},"Built-in",[381,388,389],{},"Webhook \u002F poll \u002F CLI",[381,391,392],{},"Wire up a new chat surface",[360,394,395,398,401,404],{},[381,396,397],{},"Tool",[381,399,400],{},"Built-in or custom",[381,402,403],{},"Agent (model decides)",[381,405,406],{},"Give the agent a new capability",[360,408,409,411,414,416],{},[381,410,118],{},[381,412,413],{},"Built-in (one tool)",[381,415,403],{},[381,417,418],{},"Open the lid on full PHP and shell access",[360,420,421,424,429,431],{},[381,422,423],{},"Skill",[381,425,426],{},[187,427,428],{},"laraclaw\u002Fskills\u002F{name}\u002FSKILL.md",[381,430,403],{},[381,432,433],{},"Reusable procedure or output format",[360,435,436,439,444,447],{},[381,437,438],{},"Persona",[381,440,441],{},[187,442,443],{},"laraclaw\u002Fpersonas\u002F{name}.md",[381,445,446],{},"Per-thread, switched explicitly",[381,448,449],{},"Change tone and writing style",[360,451,452,455,458,461],{},[381,453,454],{},"Command",[381,456,457],{},"Service-provider registration",[381,459,460],{},"Runs before the agent",[381,462,463],{},"Deterministic shortcut, no AI",[145,465,467],{"id":466},"the-agent-loop","The Agent Loop",[150,469,470],{},"Every message goes through the same pipeline, regardless of which connector it came in on. Let's trace it:",[472,473,478],"pre",{"className":474,"code":476,"language":477},[475],"language-text","Connector (webhook, IMAP, CLI)\n        │\n        ▼\nIncomingMessage (uuid, text, attachments, key)\n        │\n        ▼\nCommandRegistry::match()        ← short-circuit if a command matches\n        │\n        ▼\nThread::forMessage()            ← persona, conversation_id, is_direct_message\n        │\n        ▼\nChatBotAgent (laravel\u002Fai)\n  • system prompt = default + persona + current time\n  • tools: built-in + conditional + custom\n  • middleware: TranscribeAudio, EmbedConversation, LogAgentRequest\n        │\n        ▼\nConnector::reply($thread, $text, $outboundAttachments)\n","text",[187,479,476],{"__ignoreMap":480},"",[150,482,483],{},"Here's what's happening:",[485,486,487,494,507,520,536,548],"ol",{},[488,489,490,493],"li",{},[165,491,492],{},"A connector receives a message"," — Telegram pings the webhook, IMAP polls a new email, you type into the terminal.",[488,495,496,502,503,506],{},[165,497,498,499],{},"It builds an ",[187,500,501],{},"IncomingMessage"," — a DTO with a UUID, the text, any inbound attachments, and a ",[187,504,505],{},"key"," identifying the conversation.",[488,508,509,516,517,519],{},[165,510,511,512,515],{},"The ",[187,513,514],{},"CommandRegistry"," checks for an exact-match command."," If one matches (like ",[187,518,343],{},"), it handles the message and the agent is never invoked.",[488,521,522,528,529,532,533,535],{},[165,523,246,524,527],{},[187,525,526],{},"Thread"," is found or created"," — keyed by ",[187,530,531],{},"(connector, key)",". This is the persistent conversation record. It stores the ",[187,534,189],{}," conversation ID, so multi-turn context survives across messages.",[488,537,538,544,545,547],{},[165,539,511,540,543],{},[187,541,542],{},"ChatBotAgent"," runs"," — the system prompt, current persona, and tool list get assembled, and ",[187,546,189],{}," does the heavy lifting of the chat completion + tool-calling loop.",[488,549,550,553],{},[165,551,552],{},"The connector replies"," — back through the same channel, with any files the agent staged for delivery.",[150,555,556,557,559],{},"For DMs the ",[187,558,505],{}," is the user's account identifier; for groups it's the channel or thread identifier.",[145,561,563],{"id":562},"the-data-model","The Data Model",[150,565,566,567,570],{},"Laraclaw publishes five tables. All of them are prefixed ",[187,568,569],{},"laraclaw_",":",[354,572,573,586],{},[357,574,575],{},[360,576,577,580,583],{},[363,578,579],{},"Table",[363,581,582],{},"Purpose",[363,584,585],{},"Key columns",[376,587,588,611,635,662,692],{},[360,589,590,594,601],{},[381,591,592],{},[187,593,221],{},[381,595,596,597,600],{},"Maps a connector-side identifier (Slack user ID, Telegram chat ID, email address, API token hash) to your ",[187,598,599],{},"users"," table",[381,602,603,253,606,253,608],{},[187,604,605],{},"user_id",[187,607,249],{},[187,609,610],{},"account",[360,612,613,618,621],{},[381,614,615],{},[187,616,617],{},"laraclaw_threads",[381,619,620],{},"One row per ongoing conversation. The unit the agent reasons about",[381,622,623,253,625,253,627,253,630,253,633],{},[187,624,249],{},[187,626,505],{},[187,628,629],{},"conversation_id",[187,631,632],{},"is_direct_message",[187,634,319],{},[360,636,637,642,645],{},[381,638,639],{},[187,640,641],{},"laraclaw_reminders",[381,643,644],{},"One-shot scheduled prompts",[381,646,647,253,649,253,651,253,653,253,656,253,659],{},[187,648,605],{},[187,650,249],{},[187,652,505],{},[187,654,655],{},"message",[187,657,658],{},"remind_at",[187,660,661],{},"sent_at",[360,663,664,669,672],{},[381,665,666],{},[187,667,668],{},"laraclaw_heartbeats",[381,670,671],{},"Recurring scheduled prompts driven by cron expressions",[381,673,674,253,676,253,678,253,680,253,683,253,686,253,689],{},[187,675,605],{},[187,677,249],{},[187,679,505],{},[187,681,682],{},"prompt",[187,684,685],{},"cron",[187,687,688],{},"is_active",[187,690,691],{},"last_run_at",[360,693,694,699,702],{},[381,695,696],{},[187,697,698],{},"laraclaw_embeddings",[381,700,701],{},"RAG memory chunks. One row per chunk, keyed by content hash",[381,703,704,253,706,253,709,253,712,253,715,253,718,253,721],{},[187,705,605],{},[187,707,708],{},"source_type",[187,710,711],{},"source_id",[187,713,714],{},"content",[187,716,717],{},"content_hash",[187,719,720],{},"embedding",[187,722,723],{},"metadata",[150,725,726],{},"A few things worth flagging:",[728,729,730,738,750],"ul",{},[488,731,732,737],{},[165,733,734,736],{},[187,735,698],{}," is shared per owner."," There is exactly one memory pool per install, and every retrieval pulls from it. Threads do not have their own memory.",[488,739,740,749],{},[165,741,742,745,746,748],{},[187,743,744],{},"laraclaw_threads.conversation_id"," references a UUID owned by ",[187,747,189],{},"'s own tables"," — the actual message history lives there. We deliberately don't add a foreign key to avoid coupling our migrations to a third-party schema.",[488,751,752,757],{},[165,753,754,755],{},"Everything is owner-scoped via ",[187,756,605],{}," even though there's only one owner. The column is there so you can clear or audit per user if you ever migrate.",[145,759,761],{"id":760},"whats-next","What's Next",[150,763,764],{},"Now you know the moving parts. Pick where you want to go:",[728,766,767,772,777,782,787],{},[488,768,769,771],{},[181,770,25],{"href":26}," — install, run the wizard, send your first message in five minutes.",[488,773,774,776],{},[181,775,29],{"href":30}," — the full install reference.",[488,778,779,781],{},[181,780,33],{"href":40}," — wire up the chat surfaces your owner will use.",[488,783,784,786],{},[181,785,64],{"href":71}," — give the agent the capabilities it needs to be useful.",[488,788,789,791],{},[181,790,13],{"href":14}," — bend Laraclaw without writing a tool: rate limits, prompts, commands, events.",[150,793,794],{},"Ready? Let's dive in!",{"title":480,"searchDepth":796,"depth":796,"links":797},2,[798,799,800,810,811,812],{"id":147,"depth":796,"text":148},{"id":193,"depth":796,"text":194},{"id":235,"depth":796,"text":236,"children":801},[802,804,805,806,807,808,809],{"id":243,"depth":803,"text":33},3,{"id":268,"depth":803,"text":64},{"id":283,"depth":803,"text":118},{"id":299,"depth":803,"text":122},{"id":314,"depth":803,"text":136},{"id":329,"depth":803,"text":330},{"id":351,"depth":803,"text":352},{"id":466,"depth":796,"text":467},{"id":562,"depth":796,"text":563},{"id":760,"depth":796,"text":761},"What Laraclaw is, who it's for, the moving parts, and how the agent loop works.","md",null,{},true,{"title":5,"description":813},"K2G7FgFPl9M_syEvq6CK7tBqViumawtfi8RIQHHiveY",[815,821],{"title":9,"path":10,"stem":11,"description":822,"children":-1},"Give the agent persistent memory of past conversations and attached documents using RAG.",1786661905930]