[{"data":1,"prerenderedAt":641},["ShallowReactive",2],{"navigation_docs":3,"-tools-read-database":139,"-tools-read-database-surround":636},[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":110,"body":141,"description":629,"extension":630,"links":631,"meta":632,"navigation":633,"path":111,"seo":634,"stem":112,"__hash__":635},"docs\u002F6.tools\u002F8.read-database.md",{"type":142,"value":143,"toc":619},"minimark",[144,148,152,155,158,162,165,203,210,214,217,242,245,272,275,305,309,348,355,359,366,444,451,455,458,482,489,493,496,530,533,550,554,571,615],[145,146,5],"h2",{"id":147},"introduction",[149,150,151],"p",{},"The Read Database tool runs ad-hoc SQL against your application database through a connection that is read-only at the database layer. Writes don't get blocked by the tool — they get rejected by the database itself, because the connection has no grants (MySQL and Postgres) or is opened in read-only mode (SQLite).",[149,153,154],{},"When enabled, the tool also injects your schema (tables, columns, foreign keys) into the agent's system prompt, so the agent can write joins without guessing column names.",[149,156,157],{},"It's disabled by default.",[145,159,161],{"id":160},"how-read-only-is-enforced","How Read-Only Is Enforced",[149,163,164],{},"The enforcement is at the connection level, not at the tool level. There is no SQL parsing or write-statement allowlist.",[166,167,168,185],"ul",{},[169,170,171,175,176,180,181,184],"li",{},[172,173,174],"strong",{},"MySQL and Postgres"," — the tool uses a separate database user whose only grant is ",[177,178,179],"code",{},"SELECT"," on your schema. Even if the agent emits ",[177,182,183],{},"UPDATE",", the DB rejects it with a permission error.",[169,186,187,190,191,194,195,198,199,202],{},[172,188,189],{},"SQLite"," — the tool opens the same file in read-only mode (",[177,192,193],{},"file:\u002Fpath?mode=ro",") and re-asserts ",[177,196,197],{},"PRAGMA query_only = ON"," before every query, so writes through the main file or any ",[177,200,201],{},"ATTACH","-ed database are blocked.",[149,204,205,206,209],{},"This means the trust boundary lives where you can audit it (",[177,207,208],{},"SHOW GRANTS",", the SQLite PRAGMA) rather than in PHP code the agent could in principle talk its way around.",[145,211,213],{"id":212},"enabling-read-database","Enabling Read Database",[149,215,216],{},"Run the wizard:",[218,219,224],"pre",{"className":220,"code":221,"language":222,"meta":223,"style":223},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","php artisan laraclaw:setup-read-database\n","bash","",[177,225,226],{"__ignoreMap":223},[227,228,231,235,239],"span",{"class":229,"line":230},"line",1,[227,232,234],{"class":233},"sBMFI","php",[227,236,238],{"class":237},"sfazB"," artisan",[227,240,241],{"class":237}," laraclaw:setup-read-database\n",[149,243,244],{},"It detects your default DB driver and:",[166,246,247,261,266],{},[169,248,249,252,253,256,257,260],{},[172,250,251],{},"MySQL, MariaDB, Postgres"," — prints the ",[177,254,255],{},"CREATE USER"," \u002F ",[177,258,259],{},"GRANT SELECT"," SQL you'll need to run as a DB admin, then prompts for the read-only username and password and verifies the connection actually has read access.",[169,262,263,265],{},[172,264,189],{}," — flips the env flag. No credentials needed; the same file is opened in read-only mode.",[169,267,268,271],{},[172,269,270],{},"Other drivers"," — disables the tool.",[149,273,274],{},"You can also set the env vars directly:",[218,276,280],{"className":277,"code":278,"language":279,"meta":223,"style":223},"language-env shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","LARACLAW_READ_DATABASE_ENABLED=true\nLARACLAW_READ_DATABASE_USERNAME=laraclaw_reader\nLARACLAW_READ_DATABASE_PASSWORD=...\nLARACLAW_READ_DATABASE_TIMEOUT_SECONDS=10\n","env",[177,281,282,287,293,299],{"__ignoreMap":223},[227,283,284],{"class":229,"line":230},[227,285,286],{},"LARACLAW_READ_DATABASE_ENABLED=true\n",[227,288,290],{"class":229,"line":289},2,[227,291,292],{},"LARACLAW_READ_DATABASE_USERNAME=laraclaw_reader\n",[227,294,296],{"class":229,"line":295},3,[227,297,298],{},"LARACLAW_READ_DATABASE_PASSWORD=...\n",[227,300,302],{"class":229,"line":301},4,[227,303,304],{},"LARACLAW_READ_DATABASE_TIMEOUT_SECONDS=10\n",[145,306,308],{"id":307},"running-queries","Running Queries",[310,311,312,328],"table",{},[313,314,315],"thead",{},[316,317,318,322,325],"tr",{},[319,320,321],"th",{},"Parameter",[319,323,324],{},"Required",[319,326,327],{},"Description",[329,330,331],"tbody",{},[316,332,333,339,342],{},[334,335,336],"td",{},[177,337,338],{},"query",[334,340,341],{},"Yes",[334,343,344,345,347],{},"A single SQL ",[177,346,179],{}," statement",[149,349,350,351,354],{},"The result is returned as a JSON array of rows. A trailing semicolon is stripped. On failure, the response is ",[177,352,353],{},"{\"error\": \"...\"}"," so the agent can see what went wrong and try again.",[145,356,358],{"id":357},"output-limits","Output Limits",[149,360,361,362,365],{},"Results are capped at ",[172,363,364],{},"500 rows",". If the cursor returns more, the response is wrapped:",[218,367,371],{"className":368,"code":369,"language":370,"meta":223,"style":223},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"rows\": [...],\n  \"truncated\": true,\n  \"note\": \"Result exceeded 500 rows; add LIMIT or refine the query to see the rest.\"\n}\n","json",[177,372,373,379,404,418,438],{"__ignoreMap":223},[227,374,375],{"class":229,"line":230},[227,376,378],{"class":377},"sMK4o","{\n",[227,380,381,384,388,391,394,397,401],{"class":229,"line":289},[227,382,383],{"class":377},"  \"",[227,385,387],{"class":386},"spNyl","rows",[227,389,390],{"class":377},"\"",[227,392,393],{"class":377},":",[227,395,396],{"class":377}," [",[227,398,400],{"class":399},"sTEyZ","...",[227,402,403],{"class":377},"],\n",[227,405,406,408,411,413,415],{"class":229,"line":295},[227,407,383],{"class":377},[227,409,410],{"class":386},"truncated",[227,412,390],{"class":377},[227,414,393],{"class":377},[227,416,417],{"class":377}," true,\n",[227,419,420,422,425,427,429,432,435],{"class":229,"line":301},[227,421,383],{"class":377},[227,423,424],{"class":386},"note",[227,426,390],{"class":377},[227,428,393],{"class":377},[227,430,431],{"class":377}," \"",[227,433,434],{"class":237},"Result exceeded 500 rows; add LIMIT or refine the query to see the rest.",[227,436,437],{"class":377},"\"\n",[227,439,441],{"class":229,"line":440},5,[227,442,443],{"class":377},"}\n",[149,445,446,447,450],{},"The note nudges the agent toward adding a ",[177,448,449],{},"LIMIT"," clause rather than blindly retrying.",[145,452,454],{"id":453},"query-timeouts","Query Timeouts",[149,456,457],{},"A per-query timeout is set on every call:",[166,459,460,469,477],{},[169,461,462,465,466],{},[172,463,464],{},"MySQL and MariaDB"," — ",[177,467,468],{},"SET SESSION MAX_EXECUTION_TIME",[169,470,471,465,474],{},[172,472,473],{},"Postgres",[177,475,476],{},"SET statement_timeout",[169,478,479,481],{},[172,480,189],{}," — no equivalent; falls back to PHP's request time limit",[149,483,484,485,488],{},"The default is 10 seconds. Set ",[177,486,487],{},"LARACLAW_READ_DATABASE_TIMEOUT_SECONDS=0"," to disable.",[145,490,492],{"id":491},"schema-in-the-prompt","Schema in the Prompt",[149,494,495],{},"When the tool is enabled, the agent's system prompt is appended with a description of your schema:",[166,497,498,514,522],{},[169,499,500,502,503,256,506,509,510,513],{},[172,501,189],{}," — every ",[177,504,505],{},"CREATE TABLE",[177,507,508],{},"CREATE INDEX"," from ",[177,511,512],{},"sqlite_master",".",[169,515,516,465,518,521],{},[172,517,464],{},[177,519,520],{},"SHOW CREATE TABLE"," for every table.",[169,523,524,526,527,529],{},[172,525,473],{}," — column and foreign key metadata as JSON (there is no single ",[177,528,520],{}," equivalent).",[149,531,532],{},"The snapshot is cached for one hour. After running migrations, clear the cache to refresh:",[218,534,536],{"className":220,"code":535,"language":222,"meta":223,"style":223},"php artisan cache:forget laraclaw:read_database:schema\n",[177,537,538],{"__ignoreMap":223},[227,539,540,542,544,547],{"class":229,"line":230},[227,541,234],{"class":233},[227,543,238],{"class":237},[227,545,546],{"class":237}," cache:forget",[227,548,549],{"class":237}," laraclaw:read_database:schema\n",[145,551,553],{"id":552},"security-considerations","Security Considerations",[555,556,557],"blockquote",{},[149,558,559,562,563,566,567,570],{},[227,560,561],{},"!NOTE","\nRead Database is the ",[172,564,565],{},"narrower"," alternative to ",[568,569,118],"a",{"href":119},". If all you need is \"let the agent answer questions about my data\", enable this and leave Tinker off — it has a much tighter blast radius.",[166,572,573,587,593,602],{},[169,574,575,578,579,582,583,586],{},[172,576,577],{},"The agent can read everything the read-only user can read."," Audit your grants. If ",[177,580,581],{},"laraclaw_reader"," can see the ",[177,584,585],{},"payment_methods"," table, the agent can too.",[169,588,589,592],{},[172,590,591],{},"Inbound messages can influence prompts."," Anyone who can DM the bot can in principle convince the agent to run a query. Trust your trusted senders.",[169,594,595,601],{},[172,596,597,598],{},"Set ",[177,599,600],{},"LARACLAW_LOG_AGENT_REQUESTS=true"," to keep an audit trail of every query the agent has run.",[169,603,604,607,608,611,612,513],{},[172,605,606],{},"Self-describing schemas help."," A ",[177,609,610],{},"users.last_login_at"," column will be queried correctly far more often than ",[177,613,614],{},"users.lla",[616,617,618],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}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}",{"title":223,"searchDepth":289,"depth":289,"links":620},[621,622,623,624,625,626,627,628],{"id":147,"depth":289,"text":5},{"id":160,"depth":289,"text":161},{"id":212,"depth":289,"text":213},{"id":307,"depth":289,"text":308},{"id":357,"depth":289,"text":358},{"id":453,"depth":289,"text":454},{"id":491,"depth":289,"text":492},{"id":552,"depth":289,"text":553},"Let the agent run SELECT queries against your application database through a read-only connection.","md",null,{},true,{"title":110,"description":629},"ONuQmHOzDkHDujO6ZPXrd_PJpLbkTkKCx5ADfwWZ3RE",[637,639],{"title":106,"path":107,"stem":108,"description":638,"children":-1},"List, create, update, and delete events on Google Calendar or Apple CalDAV.",{"title":114,"path":115,"stem":116,"description":640,"children":-1},"Let the agent fetch and interact with JavaScript-rendered pages through Lightpanda.",1786661906119]