[{"data":1,"prerenderedAt":8079},["ShallowReactive",2],{"docs-en:all":3},[4,263,574,1214,1619,1991,2250,2920,3665,3870,5298,5660,6012,6469,6749,7028,7497,7933],{"id":5,"title":6,"body":7,"description":250,"extension":251,"meta":252,"navTitle":6,"navigation":253,"order":254,"path":255,"seo":256,"stem":257,"toc":258,"__hash__":262},"docs_en/docs/welcome.md","Welcome",{"type":8,"value":9,"toc":243},"minimark",[10,46,215],[11,12,16,17,16,21,16,25,16,28],"section",{"id":13,"className":14},"what-openpets-is",[15],"docs-section","\n  ",[18,19,20],"h2",{"id":13},"What OpenPets is",[22,23,24],"p",{},"\n    OpenPets is a small open-source desktop app that puts an animated pet on\n    your screen and lets your AI coding assistant react through it. When the\n    assistant is thinking, editing, running tests, waiting for approval, or\n    finishing a task, the pet shows a matching reaction or a short status\n    message.\n  ",[22,26,27],{},"\n    OpenPets is local-first. The desktop app, the MCP server, and the CLI all\n    talk to each other over a local socket on your machine. The only outbound\n    network calls the app makes are to download pets you choose to install and\n    to check for OpenPets updates. There is no telemetry.\n  ",[22,29,30,31,35,36,39,40,45],{},"\n    OpenPets works with any MCP-capable assistant. It has dedicated, one-click\n    integrations for ",[32,33,34],"strong",{},"Claude Code"," and ",[32,37,38],{},"OpenCode",";\n    other clients such as Cursor, VS Code, Windsurf, and Zed can connect using\n    the standard stdio MCP command shown on the\n    ",[41,42,44],"nuxtlink",{"to":43},"/docs/mcp","MCP reference"," page.\n  ",[11,47,16,50,16,53,16,64],{"id":48,"className":49},"how-the-docs-are-organized",[15],[18,51,52],{"id":48},"How the docs are organized",[22,54,55,56,60,61,63],{},"\n    This single page contains the full documentation, stacked top to bottom.\n    Each section is also a standalone page you can link directly — for example\n    ",[57,58,59],"code",{},"/docs/concepts"," or ",[57,62,43],{},". The sidebar on the\n    left groups anchors by section so you can jump anywhere.\n  ",[65,66,69,70,16],"div",{"className":67},[68],"docs-table-wrap","\n    ",[71,72,73,74,73,88,69],"table",{},"\n      ",[75,76,77,78,73],"thead",{},"\n        ",[79,80,81,85],"tr",{},[82,83,84],"th",{},"If you want to…",[82,86,87],{},"Read",[89,90,77,91,77,103,77,113,77,123,77,134,77,145,77,155,77,166,77,177,77,188,77,204,73],"tbody",{},[79,92,93,97],{},[94,95,96],"td",{},"Get started in five minutes",[94,98,99],{},[41,100,102],{"to":101},"/docs/quickstart","Quick start",[79,104,105,108],{},[94,106,107],{},"Understand the mental model",[94,109,110],{},[41,111,112],{"to":59},"How OpenPets works",[79,114,115,118],{},[94,116,117],{},"Install the desktop app",[94,119,120],{},[41,121,117],{"to":122},"/docs/install",[79,124,125,128],{},[94,126,127],{},"Connect Claude Code or OpenCode",[94,129,130],{},[41,131,133],{"to":132},"/docs/ai-assistants","Set up AI assistants",[79,135,136,139],{},[94,137,138],{},"Install reminders, timers, or GitHub notifications",[94,140,141],{},[41,142,144],{"to":143},"/docs/plugins","Plugin guide",[79,146,147,150],{},[94,148,149],{},"Wire up a different MCP client",[94,151,152],{},[41,153,154],{"to":43},"MCP server reference",[79,156,157,160],{},[94,158,159],{},"Look up CLI commands",[94,161,162],{},[41,163,165],{"to":164},"/docs/cli","CLI reference",[79,167,168,171],{},[94,169,170],{},"Package or submit a pet",[94,172,173],{},[41,174,176],{"to":175},"/docs/pet-format","Pet file format",[79,178,179,182],{},[94,180,181],{},"Build or validate a desktop plugin",[94,183,184],{},[41,185,187],{"to":186},"/docs/developer#plugins","Developer plugin notes",[79,189,190,193],{},[94,191,192],{},"Know exactly what OpenPets writes on disk or sends over the network",[94,194,195,199,200],{},[41,196,198],{"to":197},"/docs/files-and-config","Local files"," · ",[41,201,203],{"to":202},"/docs/privacy","Privacy",[79,205,206,209],{},[94,207,208],{},"Diagnose something that is not working",[94,210,211],{},[41,212,214],{"to":213},"/docs/troubleshooting","Troubleshooting",[11,216,16,219,16,222],{"id":217,"className":218},"where-to-start",[15],[18,220,221],{"id":217},"Where to start",[223,224,69,225,69,232,69,237,16],"ul",{},[226,227,228,229,231],"li",{},"If you have not installed OpenPets yet, start with ",[41,230,102],{"to":101},".",[226,233,234,235,231],{},"If you have it installed and want to connect an assistant, jump to ",[41,236,133],{"to":132},[226,238,239,240,242],{},"If you are an integrator, plugin author, or just curious about the architecture, read ",[41,241,112],{"to":59}," first.",{"title":244,"searchDepth":245,"depth":245,"links":246},"",2,[247,248,249],{"id":13,"depth":245,"text":20},{"id":48,"depth":245,"text":52},{"id":217,"depth":245,"text":221},"OpenPets is an open-source desktop pet for AI coding agents. This page explains what it is, how to navigate the docs, and where to start.","md",{},true,0,"/docs/welcome",{"title":6,"description":250},"docs/welcome",[259,260,261],{"id":13,"label":20},{"id":48,"label":52},{"id":217,"label":221},"Cr6SMQeg1tT_mVsBz2X_xieoUzEJX0SAdvfxSjGsTbo",{"id":264,"title":102,"body":265,"description":562,"extension":251,"meta":563,"navTitle":102,"navigation":253,"order":564,"path":101,"seo":565,"stem":566,"toc":567,"__hash__":573},"docs_en/docs/quickstart.md",{"type":8,"value":266,"toc":555},[267,358,401,471,523],[11,268,16,271,16,275,16,278,16,352],{"id":269,"className":270},"install-app",[15],[18,272,274],{"id":273},"_1-install-the-desktop-app","1. Install the desktop app",[22,276,277],{},"\n    Download the latest OpenPets release for your operating system and install\n    it. The installers are unsigned today, so each operating system asks you\n    to confirm the first launch.\n  ",[65,279,69,281,16],{"className":280},[68],[71,282,73,283,73,296,69],{},[75,284,77,285,73],{},[79,286,287,290,293],{},[82,288,289],{},"Platform",[82,291,292],{},"Download",[82,294,295],{},"First-launch note",[89,297,77,298,77,316,77,329,73],{},[79,299,300,301,300,304,300,309,77],{},"\n          ",[94,302,303],{},"macOS",[94,305,306],{},[57,307,308],{},"OpenPets-\u003Cversion>-mac-\u003Carch>.dmg",[94,310,311,312,315],{},"Drag to Applications. If Gatekeeper blocks the app, right-click the icon and choose ",[32,313,314],{},"Open"," the first time.",[79,317,300,318,300,321,300,326,77],{},[94,319,320],{},"Windows",[94,322,323],{},[57,324,325],{},"OpenPets-\u003Cversion>-win-x64-setup.exe",[94,327,328],{},"Run the installer and pick a destination. Approve the SmartScreen warning if it appears.",[79,330,300,331,300,334,300,345,77],{},[94,332,333],{},"Linux",[94,335,336,199,339,199,342],{},[57,337,338],{},"OpenPets-\u003Cversion>-linux-\u003Carch>.AppImage",[57,340,341],{},".deb",[57,343,344],{},".tar.gz",[94,346,347,348,351],{},"For AppImage, mark it executable (",[57,349,350],{},"chmod +x",") and run it.",[22,353,354,355,357],{},"\n    See ",[41,356,117],{"to":122}," for the\n    full per-platform walkthrough, including how to handle Gatekeeper and\n    SmartScreen, and how to uninstall.\n  ",[11,359,16,362,16,366,16,16,379,16,394],{"id":360,"className":361},"pick-pet",[15],[18,363,365],{"id":364},"_2-pick-a-pet","2. Pick a pet",[22,367,368,369,372,373,378],{},"\n    When OpenPets launches it lives in the system tray, not on the dock. Click\n    the tray icon and open ",[32,370,371],{},"Pet Manager",". You can install pets\n    from the bundled gallery or browse all available pets at\n    ",[374,375,377],"a",{"href":376},"/gallery","openpets.dev/gallery",".\n  ",[223,380,69,381,69,388,69,391,16],{},[226,382,383,384,387],{},"Click ",[32,385,386],{},"Install"," on the pet you like.",[226,389,390],{},"The desktop app downloads the pet package and extracts it locally.",[226,392,393],{},"Once installed, set it as the default if you want it to appear at startup.",[22,395,396,397,400],{},"\n    Installation is local. The desktop app fetches the catalog and the pet ZIP\n    over HTTPS, validates them, and writes them under your user data\n    directory. Nothing else leaves your machine. See\n    ",[41,398,399],{"to":202},"Privacy & network behaviour"," for\n    the exact request list.\n  ",[11,402,16,405,16,409,16,16,416,16,455,16,460],{"id":403,"className":404},"connect-assistant",[15],[18,406,408],{"id":407},"_3-connect-your-assistant","3. Connect your assistant",[22,410,411,412,415],{},"\n    Open the tray menu, choose ",[32,413,414],{},"Integrations",", and pick your\n    AI assistant. OpenPets ships dedicated cards for Claude Code and OpenCode.\n  ",[65,417,69,419,16],{"className":418},[68],[71,420,73,421,73,431,69],{},[75,422,77,423,73],{},[79,424,425,428],{},[82,426,427],{},"Assistant",[82,429,430],{},"What \"Install\" does",[89,432,77,433,77,446,73],{},[79,434,300,435,300,439,77],{},[94,436,437],{},[32,438,34],{},[94,440,441,442,445],{},"Adds an MCP server called ",[57,443,444],{},"openpets"," to Claude at user scope, and writes a small managed instructions file so Claude knows when to use OpenPets.",[79,447,300,448,300,452,77],{},[94,449,450],{},[32,451,38],{},[94,453,454],{},"Writes the OpenPets MCP entry, OpenCode plugin, and managed instructions into your global OpenCode config.",[22,456,457,458,378],{},"\n    Other MCP-capable assistants (Cursor, Windsurf, VS Code MCP, Zed,\n    Claude Desktop, etc.) don't have a dedicated card yet. To wire them up,\n    use the standard stdio command shown on\n    ",[41,459,154],{"to":43},[22,461,462,463,466,467,470],{},"\n    Hooks are ",[32,464,465],{},"not"," installed by the basic flow. Hooks are an\n    opt-in extra that modifies your assistant's hook settings file to produce\n    automatic reactions. Open ",[32,468,469],{},"Configure"," on the Claude Code\n    card if you want to enable them.\n  ",[11,472,16,475,16,479,16,482,16,503,16,517],{"id":473,"className":474},"verify",[15],[18,476,478],{"id":477},"_4-verify-it-works","4. Verify it works",[22,480,481],{},"\n    Restart your assistant after installing the integration so it picks up the\n    new MCP server. Then ask it to check OpenPets:\n  ",[65,483,69,486,69,497,16],{"className":484},[485],"docs-code",[65,487,490,494],{"className":488},[489],"docs-code-bar",[491,492,493],"span",{},"Prompt",[491,495,496],{},"text",[498,499,500],"pre",{},[57,501,502],{},"Can you call openpets_status and tell me which pet I have configured?",[22,504,505,506,509,510,35,513,516],{},"\n    The assistant should call the ",[57,507,508],{},"openpets_status"," tool and reply\n    with the running app version and the targeted pet. You can also try\n    ",[57,511,512],{},"openpets_react",[57,514,515],{},"openpets_say"," to see the pet\n    change reaction or show a brief message.\n  ",[22,518,519,520,522],{},"\n    If the assistant says OpenPets is unavailable, check that the desktop app\n    is still running in the tray and that you restarted the assistant after\n    installing the integration. See\n    ",[41,521,214],{"to":213}," if it\n    still does not connect.\n  ",[11,524,16,527,16,530],{"id":525,"className":526},"next-steps",[15],[18,528,529],{"id":525},"Next steps",[223,531,69,532,69,538,69,545,69,552,16],{},[226,533,534,535,537],{},"Read ",[41,536,112],{"to":59}," to understand default vs agent pets, leases, and what reactions are available.",[226,539,540,541,231],{},"For deeper Claude Code setup including hooks, see ",[41,542,544],{"to":543},"/integrations/claude","the Claude Code integration guide",[226,546,547,548,231],{},"For OpenCode setup including the plugin, see ",[41,549,551],{"to":550},"/integrations/opencode","the OpenCode integration guide",[226,553,554],{},"For everything else (CLI, file format, exact files OpenPets writes), keep scrolling or use the sidebar.",{"title":244,"searchDepth":245,"depth":245,"links":556},[557,558,559,560,561],{"id":273,"depth":245,"text":274},{"id":364,"depth":245,"text":365},{"id":407,"depth":245,"text":408},{"id":477,"depth":245,"text":478},{"id":525,"depth":245,"text":529},"Install OpenPets, add your first pet, and connect your AI assistant in about five minutes.",{},10,{"title":102,"description":562},"docs/quickstart",[568,569,570,571,572],{"id":269,"label":274},{"id":360,"label":365},{"id":403,"label":408},{"id":473,"label":478},{"id":525,"label":529},"G1gn4eXwbvt47XovCn2JQAiND_Z2BqBpxcVB2Tv0RaY",{"id":575,"title":112,"body":576,"description":1200,"extension":251,"meta":1201,"navTitle":1202,"navigation":253,"order":1203,"path":59,"seo":1204,"stem":1205,"toc":1206,"__hash__":1213},"docs_en/docs/concepts.md",{"type":8,"value":577,"toc":1189},[578,653,750,888,959,1042],[11,579,16,582,16,585,16,588,16,647,16,650],{"id":580,"className":581},"default-vs-agent-pets",[15],[18,583,584],{"id":580},"Default vs agent pets",[22,586,587],{},"\n    OpenPets distinguishes between two kinds of pet windows on your desktop.\n  ",[65,589,69,591,16],{"className":590},[68],[71,592,73,593,73,606,69],{},[75,594,77,595,73],{},[79,596,597,600,603],{},[82,598,599],{},"Kind",[82,601,602],{},"When it shows",[82,604,605],{},"Who controls it",[89,607,77,608,77,621,77,634,73],{},[79,609,300,610,300,615,300,618,77],{},[94,611,612],{},[32,613,614],{},"Default pet",[94,616,617],{},"Always, unless you hide it from the tray menu.",[94,619,620],{},"You. The tray controls visibility, position, and pause state.",[79,622,300,623,300,628,300,631,77],{},[94,624,625],{},[32,626,627],{},"Agent pet",[94,629,630],{},"Only while an assistant is actively using OpenPets.",[94,632,633],{},"The assistant. The pet window opens when an assistant requests a specific pet, and closes when the assistant stops requesting it.",[79,635,300,636,300,641,300,644,77],{},[94,637,638],{},[32,639,640],{},"Built-in pet",[94,642,643],{},"Whenever the default pet is missing or broken.",[94,645,646],{},"OpenPets. This is the bundled fallback that ships with the app so it is always available.",[22,648,649],{},"\n    The default pet is the everyday companion. Agent pets are useful when you\n    have many assistants running at once and want each to drive its own pet, or\n    when you have a specific pet you want a specific assistant to use.\n  ",[22,651,652],{},"\n    If an assistant requests a pet that is not installed or is broken, OpenPets\n    routes the events to the default pet instead of failing. The status\n    response includes a fallback reason so the assistant can tell what\n    happened.\n  ",[11,654,16,657,16,660,16,667,16,731,16,734],{"id":655,"className":656},"leases-and-routing",[15],[18,658,659],{"id":655},"Leases and routing",[22,661,662,663,666],{},"\n    An assistant does not send pet reactions directly. It first asks OpenPets\n    for a ",[32,664,665],{},"lease"," on a pet. The lease is a short ticket that\n    says \"for the next few seconds, route my reactions and messages to this\n    pet\". Leases let several assistants share OpenPets without stepping on\n    each other.\n  ",[65,668,69,670,16],{"className":669},[68],[71,671,73,672,73,682,69],{},[75,673,77,674,73],{},[79,675,676,679],{},[82,677,678],{},"Step",[82,680,681],{},"What happens",[89,683,77,684,77,696,77,704,77,715,77,723,73],{},[79,685,300,686,300,689,77],{},[94,687,688],{},"1. Acquire",[94,690,691,692,695],{},"The assistant calls ",[57,693,694],{},"lease.acquire"," with an optional pet id. OpenPets returns a lease that lasts 15 seconds.",[79,697,300,698,300,701,77],{},[94,699,700],{},"2. First explicit lease",[94,702,703],{},"If this is the first active lease for a specific (non-default) pet, OpenPets opens that pet's window.",[79,705,300,706,300,709,77],{},[94,707,708],{},"3. Heartbeat",[94,710,691,711,714],{},[57,712,713],{},"lease.heartbeat"," while it is still working. Each heartbeat extends the lease by another 15 seconds.",[79,716,300,717,300,720,77],{},[94,718,719],{},"4. React or say",[94,721,722],{},"Reactions and messages tagged with the lease id are routed to the leased pet. Reactions without a lease go to the default pet.",[79,724,300,725,300,728,77],{},[94,726,727],{},"5. Release or expire",[94,729,730],{},"When the assistant releases the lease, or 15 seconds pass with no heartbeat, the lease ends. When the last lease for a specific pet ends, OpenPets closes that pet's window.",[22,732,733],{},"\n    The MCP server included with OpenPets handles this transparently: it\n    acquires a lease at startup, heartbeats every 5 seconds, and releases on\n    shutdown. The lease id is automatically attached to every reaction and\n    message it sends.\n  ",[65,735,69,737,69,745,16],{"className":736},[485],[65,738,740,743],{"className":739},[489],[491,741,742],{},"Lease lifetimes",[491,744,496],{},[498,746,747],{},[57,748,749],{},"lease TTL          15 seconds\nheartbeat (MCP)    every 5 seconds\nserver sweep       every 5 seconds (releases expired leases)\nfallback           default pet if requested pet is missing or broken",[11,751,16,754,16,757,16,760,16,791,16,798,16,814,16,825,16,830,16,853],{"id":752,"className":753},"local-ipc",[15],[18,755,756],{"id":752},"Local IPC",[22,758,759],{},"\n    All OpenPets communication is on your machine. There is no network bus, no\n    cloud queue, no remote endpoint. The desktop app exposes a small local\n    socket that the CLI, the MCP server, and any other OpenPets client connect\n    to directly.\n  ",[65,761,69,763,16],{"className":762},[68],[71,764,73,765,73,774,69],{},[75,766,77,767,73],{},[79,768,769,771],{},[82,770,289],{},[82,772,773],{},"Transport",[89,775,77,776,77,784,73],{},[79,777,778,781],{},[94,779,780],{},"macOS, Linux",[94,782,783],{},"Unix domain socket inside a private 0700 runtime directory.",[79,785,786,788],{},[94,787,320],{},[94,789,790],{},"Named pipe scoped to the user session.",[22,792,793,794,797],{},"\n    When OpenPets starts, it writes a small ",[32,795,796],{},"discovery file","\n    that tells clients where the socket lives and which token to present.\n    Clients read the file, open the socket, send a token-stamped JSON request,\n    and read a single JSON response.\n  ",[65,799,69,801,69,809,16],{"className":800},[485],[65,802,804,807],{"className":803},[489],[491,805,806],{},"Discovery file path",[491,808,496],{},[498,810,811],{},[57,812,813],{},"macOS    ~/Library/Application Support/OpenPets/runtime/ipc.json\nWindows  %APPDATA%\\OpenPets\\runtime\\ipc.json\nLinux    $XDG_RUNTIME_DIR/openpets/ipc.json  (if private)\n         ~/.config/OpenPets/runtime/ipc.json (fallback)",[22,815,816,817,820,821,824],{},"\n    The discovery file is written with permissions ",[57,818,819],{},"0600"," inside a\n    ",[57,822,823],{},"0700"," directory. The token rotates every time the desktop app\n    starts.\n  ",[826,827,829],"h3",{"id":828},"protocol-shape","Protocol shape",[223,831,69,832,69,838,69,844,69,847,69,850,16],{},[226,833,834,835,231],{},"Protocol version: ",[57,836,837],{},"1",[226,839,840,841,231],{},"Encoding: line-delimited JSON. One JSON request per connection, terminated by ",[57,842,843],{},"\\n",[226,845,846],{},"Maximum message size: 16 KB.",[226,848,849],{},"Connect timeout: 2 seconds. Response timeout: 3 seconds.",[226,851,852],{},"Every request includes the discovery token. Wrong or missing token is rejected.",[22,854,855,856,859,860,863,864,859,867,863,870,859,872,863,874,859,877,880,881,884,885,887],{},"\n    Available methods: ",[57,857,858],{},"hello",", ",[57,861,862],{},"status",",\n    ",[57,865,866],{},"pets.list",[57,868,869],{},"pets.install",[57,871,694],{},[57,873,713],{},[57,875,876],{},"lease.release",[57,878,879],{},"pet.react",", and\n    ",[57,882,883],{},"pet.say",". See the\n    ",[41,886,44],{"to":43}," for the full schema each\n    one accepts and returns.\n  ",[11,889,16,892,16,895,16,898,16,953,16,956],{"id":890,"className":891},"mcp-and-hooks",[15],[18,893,894],{"id":890},"MCP and hooks",[22,896,897],{},"\n    There are two ways an assistant can drive your pet. MCP is the active path\n    where the assistant calls tools deliberately. Hooks are the passive path\n    where lifecycle events trigger reactions automatically.\n  ",[65,899,69,901,16],{"className":900},[68],[71,902,73,903,73,919,69],{},[75,904,77,905,73],{},[79,906,907,910,913,916],{},[82,908,909],{},"Path",[82,911,912],{},"Direction",[82,914,915],{},"What it can do",[82,917,918],{},"Available on",[89,920,77,921,77,937,73],{},[79,922,300,923,300,928,300,931,300,934,77],{},[94,924,925],{},[32,926,927],{},"MCP tools",[94,929,930],{},"Assistant calls OpenPets.",[94,932,933],{},"Check status, change reaction, show a short message.",[94,935,936],{},"Any MCP-capable assistant.",[79,938,300,939,300,944,300,947,300,950,77],{},[94,940,941],{},[32,942,943],{},"Hooks",[94,945,946],{},"Assistant lifecycle event triggers OpenPets.",[94,948,949],{},"Automatic reactions for thinking, editing, testing, waiting, success, and error.",[94,951,952],{},"Claude Code today. Optional, installed separately.",[22,954,955],{},"\n    Most users keep MCP on and hooks off. Hooks add automatic visual feedback\n    without the assistant having to call tools, but they also touch the\n    assistant's hook settings file, which is why they are an opt-in extra\n    rather than part of the basic install.\n  ",[22,957,958],{},"\n    Both paths use the same local IPC under the hood, and both go through\n    leases when targeting a specific pet.\n  ",[11,960,16,963,16,966,16,969,16,1030,16,1036],{"id":961,"className":962},"pet-assets",[15],[18,964,965],{"id":961},"Pet assets",[22,967,968],{},"\n    A pet is a small package containing one spritesheet and a metadata file.\n    OpenPets reads pets from three places.\n  ",[65,970,69,972,16],{"className":971},[68],[71,973,73,974,73,987,69],{},[75,975,77,976,73],{},[79,977,978,981,984],{},[82,979,980],{},"Source",[82,982,983],{},"What it is",[82,985,986],{},"Where it lives",[89,988,77,989,77,1001,77,1014,73],{},[79,990,300,991,300,995,300,998,77],{},[94,992,993],{},[32,994,640],{},[94,996,997],{},"The bundled fallback that ships with every desktop release.",[94,999,1000],{},"Inside the OpenPets app bundle.",[79,1002,300,1003,300,1008,300,1011,77],{},[94,1004,1005],{},[32,1006,1007],{},"Catalog pets",[94,1009,1010],{},"Pets you install from the OpenPets gallery.",[94,1012,1013],{},"Downloaded as ZIPs and extracted into the OpenPets user data directory.",[79,1015,300,1016,300,1021,300,1024,77],{},[94,1017,1018],{},[32,1019,1020],{},"Local Codex pets",[94,1022,1023],{},"Pets you are developing yourself, imported live for testing.",[94,1025,1026,1029],{},[57,1027,1028],{},"~/.codex/pets/\u003Cpet-id>/"," on your machine.",[22,1031,1032,1033,1035],{},"\n    Catalog ZIPs are validated before they are written to disk: archive size,\n    extracted size, number of entries, per-file size, path-traversal attempts,\n    and symlinks are all checked. See\n    ",[41,1034,176],{"to":175}," for the package\n    layout and validation rules.\n  ",[22,1037,1038,1039,378],{},"\n    The user data directory location depends on your operating system; the\n    exact paths are listed in\n    ",[41,1040,1041],{"to":197},"Local files & configuration",[11,1043,16,1046,16,1049,16,1057,16,1184],{"id":1044,"className":1045},"reactions",[15],[18,1047,1048],{"id":1044},"Reactions",[22,1050,1051,1052,1054,1055,378],{},"\n    Every pet supports the same fixed set of reactions. Assistants pick one\n    from this list when they call ",[57,1053,512],{}," or include a\n    reaction with ",[57,1056,515],{},[65,1058,69,1060,16],{"className":1059},[68],[71,1061,73,1062,73,1072,69],{},[75,1063,77,1064,73],{},[79,1065,1066,1069],{},[82,1067,1068],{},"Reaction",[82,1070,1071],{},"Typical meaning",[89,1073,77,1074,77,1084,77,1094,77,1104,77,1114,77,1124,77,1134,77,1144,77,1154,77,1164,77,1174,73],{},[79,1075,1076,1081],{},[94,1077,1078],{},[57,1079,1080],{},"idle",[94,1082,1083],{},"Doing nothing in particular.",[79,1085,1086,1091],{},[94,1087,1088],{},[57,1089,1090],{},"thinking",[94,1092,1093],{},"Reading or planning before acting.",[79,1095,1096,1101],{},[94,1097,1098],{},[57,1099,1100],{},"working",[94,1102,1103],{},"General-purpose \"busy\" reaction.",[79,1105,1106,1111],{},[94,1107,1108],{},[57,1109,1110],{},"editing",[94,1112,1113],{},"Modifying files.",[79,1115,1116,1121],{},[94,1117,1118],{},[57,1119,1120],{},"running",[94,1122,1123],{},"Executing a command or process.",[79,1125,1126,1131],{},[94,1127,1128],{},[57,1129,1130],{},"testing",[94,1132,1133],{},"Running tests.",[79,1135,1136,1141],{},[94,1137,1138],{},[57,1139,1140],{},"waiting",[94,1142,1143],{},"Blocked, waiting for the user's approval or input.",[79,1145,1146,1151],{},[94,1147,1148],{},[57,1149,1150],{},"waving",[94,1152,1153],{},"Greeting or attention.",[79,1155,1156,1161],{},[94,1157,1158],{},[57,1159,1160],{},"success",[94,1162,1163],{},"Task completed successfully.",[79,1165,1166,1171],{},[94,1167,1168],{},[57,1169,1170],{},"error",[94,1172,1173],{},"Something went wrong.",[79,1175,1176,1181],{},[94,1177,1178],{},[57,1179,1180],{},"celebrating",[94,1182,1183],{},"Bigger win than a normal success.",[22,1185,1186,1187,378],{},"\n    A pet only needs to provide animation frames for the reactions it cares\n    about. Reactions it does not implement fall back to ",[57,1188,1080],{},{"title":244,"searchDepth":245,"depth":245,"links":1190},[1191,1192,1193,1197,1198,1199],{"id":580,"depth":245,"text":584},{"id":655,"depth":245,"text":659},{"id":752,"depth":245,"text":756,"children":1194},[1195],{"id":828,"depth":1196,"text":829},3,{"id":890,"depth":245,"text":894},{"id":961,"depth":245,"text":965},{"id":1044,"depth":245,"text":1048},"The mental model behind OpenPets: default pet vs agent pets, leases, local IPC, MCP tools and hooks, where pet assets live, and the reactions a pet can show.",{},"Concepts",20,{"title":112,"description":1200},"docs/concepts",[1207,1208,1209,1210,1211,1212],{"id":580,"label":584},{"id":655,"label":659},{"id":752,"label":756},{"id":890,"label":894},{"id":961,"label":965},{"id":1044,"label":1048},"BFdKokOojqJtcJIaSQ5_dUHdN0slDCpUpBYhl9n1z4U",{"id":1215,"title":117,"body":1216,"description":1605,"extension":251,"meta":1606,"navTitle":386,"navigation":253,"order":1607,"path":122,"seo":1608,"stem":1609,"toc":1610,"__hash__":1618},"docs_en/docs/install.md",{"type":8,"value":1217,"toc":1596},[1218,1254,1315,1379,1468,1484,1508],[11,1219,16,1222,16,1224,16,1227,16,1243],{"id":1220,"className":1221},"download",[15],[18,1223,292],{"id":1220},[22,1225,1226],{},"\n    OpenPets releases are published on GitHub. Each release contains one\n    artifact per platform and architecture, named with the version and\n    target. The download names always follow this shape:\n  ",[65,1228,69,1230,69,1238,16],{"className":1229},[485],[65,1231,1233,1236],{"className":1232},[489],[491,1234,1235],{},"Artifact naming",[491,1237,496],{},[498,1239,1240],{},[57,1241,1242],{},"OpenPets-\u003Cversion>-mac-\u003Carch>.dmg\nOpenPets-\u003Cversion>-mac-\u003Carch>.zip\nOpenPets-\u003Cversion>-win-\u003Carch>-setup.exe\nOpenPets-\u003Cversion>-win-\u003Carch>-portable.exe\nOpenPets-\u003Cversion>-linux-\u003Carch>.AppImage\nOpenPets-\u003Cversion>-linux-\u003Carch>.deb\nOpenPets-\u003Cversion>-linux-\u003Carch>.tar.gz",[22,1244,1245,1246,1249,1250,1253],{},"\n    Each release also publishes a ",[57,1247,1248],{},"SHA256SUMS"," file you can use to\n    verify the download. The current OpenPets installers are ",[32,1251,1252],{},"not\n    code-signed",", so each operating system will warn you on first\n    launch.\n  ",[11,1255,16,1258,16,1260,16,1295,16,1312],{"id":1256,"className":1257},"macos",[15],[18,1259,303],{"id":1256},[1261,1262,69,1263,69,1270,69,1280,69,1292,16],"ol",{},[226,1264,1265,1266,1269],{},"Download the ",[57,1267,1268],{},".dmg"," matching your Mac (Apple Silicon or Intel).",[226,1271,1272,1273,1276,1277,231],{},"Open the DMG and drag ",[32,1274,1275],{},"OpenPets.app"," into ",[32,1278,1279],{},"Applications",[226,1281,1282,1283,1285,1286,1288,1289,1291],{},"The first time you launch the app, macOS Gatekeeper will block it because the build is unsigned. Right-click ",[32,1284,1275],{}," and choose ",[32,1287,314],{},", then click ",[32,1290,314],{}," in the dialog.",[226,1293,1294],{},"If macOS keeps refusing, remove the quarantine attribute manually:",[65,1296,69,1298,69,1307,16],{"className":1297},[485],[65,1299,1301,1304],{"className":1300},[489],[491,1302,1303],{},"Terminal",[491,1305,1306],{},"bash",[498,1308,1309],{},[57,1310,1311],{},"xattr -d com.apple.quarantine /Applications/OpenPets.app",[22,1313,1314],{},"\n    OpenPets hides itself from the Dock on macOS by design. After launch you\n    only see the pet (if enabled) and the tray icon in the menu bar.\n  ",[11,1316,16,1319,16,1321,16,1324,16,1369],{"id":1317,"className":1318},"windows",[15],[18,1320,320],{"id":1317},[22,1322,1323],{},"\n    Pick one of two Windows installers depending on how you want to install\n    OpenPets:\n  ",[65,1325,69,1327,16],{"className":1326},[68],[71,1328,73,1329,73,1339,69],{},[75,1330,77,1331,73],{},[79,1332,1333,1336],{},[82,1334,1335],{},"Installer",[82,1337,1338],{},"What it does",[89,1340,77,1341,77,1356,73],{},[79,1342,300,1343,300,1353,77],{},[94,1344,1345,1348,1349,1352],{},[32,1346,1347],{},"NSIS setup"," (",[57,1350,1351],{},"-setup.exe",")",[94,1354,1355],{},"Standard installer. You choose the install directory; OpenPets is installed per-user, not for all users.",[79,1357,300,1358,300,1366,77],{},[94,1359,1360,1348,1363,1352],{},[32,1361,1362],{},"Portable",[57,1364,1365],{},"-portable.exe",[94,1367,1368],{},"Self-contained executable. Run it from any folder; nothing is installed system-wide.",[22,1370,1371,1372,1375,1376,378],{},"\n    On first launch, Windows SmartScreen may show \"Windows protected your PC\"\n    because the installer is unsigned. Click ",[32,1373,1374],{},"More info",", then\n    ",[32,1377,1378],{},"Run anyway",[11,1380,16,1383,16,1385,16,1388,16,1440,16,1455],{"id":1381,"className":1382},"linux",[15],[18,1384,333],{"id":1381},[22,1386,1387],{},"\n    Three Linux artifacts are published. Pick whichever matches your distro\n    and packaging preference:\n  ",[65,1389,69,1391,16],{"className":1390},[68],[71,1392,73,1393,73,1403,69],{},[75,1394,77,1395,73],{},[79,1396,1397,1400],{},[82,1398,1399],{},"Artifact",[82,1401,1402],{},"How to run",[89,1404,77,1405,77,1415,77,1427,73],{},[79,1406,300,1407,300,1412,77],{},[94,1408,1409],{},[57,1410,1411],{},".AppImage",[94,1413,1414],{},"Make it executable, then run it. No system install required.",[79,1416,300,1417,300,1421,77],{},[94,1418,1419],{},[57,1420,341],{},[94,1422,1423,1424,231],{},"Install with ",[57,1425,1426],{},"sudo apt install ./OpenPets-\u003Cversion>-linux-\u003Carch>.deb",[79,1428,300,1429,300,1433,77],{},[94,1430,1431],{},[57,1432,344],{},[94,1434,1435,1436,1439],{},"Extract and run the ",[57,1437,1438],{},"OpenPets"," binary directly.",[65,1441,69,1443,69,1450,16],{"className":1442},[485],[65,1444,1446,1448],{"className":1445},[489],[491,1447,1303],{},[491,1449,1306],{},[498,1451,1452],{},[57,1453,1454],{},"chmod +x OpenPets-*.AppImage\n./OpenPets-*.AppImage",[22,1456,1457,1458,1461,1462,1464,1465,378],{},"\n    OpenPets uses a private runtime directory for its IPC socket. On systems\n    with a hardened ",[57,1459,1460],{},"$XDG_RUNTIME_DIR"," (mode ",[57,1463,823],{},",\n    owned by your user) it places the socket there; otherwise it falls back\n    to ",[57,1466,1467],{},"/tmp/openpets-\u003Cuid>/",[11,1469,16,1472,16,1475,16,16,1478,16,1481],{"id":1470,"className":1471},"first-launch",[15],[18,1473,1474],{"id":1470},"First launch",[22,1476,1477],{},"\n    The first time OpenPets starts it shows an onboarding window so you can\n    pick a starting pet and decide whether to enable the default pet on\n    startup. After onboarding finishes, the app sits in the system tray.\n  ",[22,1479,1480],{},"\n    On macOS, you will not see OpenPets in the Dock — the app intentionally\n    hides itself from the Dock so the pet is the only visible presence.\n    Everything you can do lives in the tray menu.\n  ",[22,1482,1483],{},"\n    If you ever close the app accidentally on Windows or Linux, click the\n    tray icon or launch OpenPets again; it uses a single-instance lock to\n    avoid running twice.\n  ",[11,1485,16,1488,16,1491,16,1494,16,1497],{"id":1486,"className":1487},"updates",[15],[18,1489,1490],{"id":1486},"Updates",[22,1492,1493],{},"\n    OpenPets checks for new releases on GitHub when it starts. If a newer\n    version is available, the tray menu shows an \"Update available\" entry\n    that links to the latest release.\n  ",[22,1495,1496],{},"\n    Updates are not installed automatically. To update:\n  ",[1261,1498,69,1499,69,1502,69,1505,16],{},[226,1500,1501],{},"Quit OpenPets from the tray menu.",[226,1503,1504],{},"Download the new installer for your platform.",[226,1506,1507],{},"Run it; your installed pets and preferences stay in place because they live in your user data directory, not in the app bundle.",[11,1509,16,1512,16,1515,16,1518,16,1586],{"id":1510,"className":1511},"uninstall",[15],[18,1513,1514],{"id":1510},"Uninstall",[22,1516,1517],{},"\n    Removing the app does not remove your installed pets, preferences, or\n    integration files. Those live outside the app bundle so updates can\n    preserve them. Delete them by hand if you want a fully clean uninstall.\n  ",[65,1519,69,1521,16],{"className":1520},[68],[71,1522,73,1523,73,1535,69],{},[75,1524,77,1525,73],{},[79,1526,1527,1529,1532],{},[82,1528,289],{},[82,1530,1531],{},"Remove the app",[82,1533,1534],{},"Optional: remove user data",[89,1536,77,1537,77,1552,77,1568,73],{},[79,1538,300,1539,300,1541,300,1547,77],{},[94,1540,303],{},[94,1542,1543,1544,1546],{},"Drag ",[32,1545,1275],{}," from Applications to the Trash.",[94,1548,1549],{},[57,1550,1551],{},"~/Library/Application Support/OpenPets",[79,1553,300,1554,300,1556,300,1563,77],{},[94,1555,320],{},[94,1557,1558,1559,1562],{},"Use ",[32,1560,1561],{},"Add or remove programs",", or delete the portable executable.",[94,1564,1565],{},[57,1566,1567],{},"%APPDATA%\\OpenPets",[79,1569,300,1570,300,1572,300,1578,77],{},[94,1571,333],{},[94,1573,1574,1575,231],{},"Delete the AppImage, or uninstall the deb with ",[57,1576,1577],{},"sudo apt remove openpets",[94,1579,1580,199,1583],{},[57,1581,1582],{},"$XDG_RUNTIME_DIR/openpets",[57,1584,1585],{},"~/.config/OpenPets",[22,1587,1588,1589,1592,1593,1595],{},"\n    If you previously installed the Claude Code or OpenCode integrations,\n    open OpenPets first and remove them from the Integrations window before\n    deleting the app. That way the managed entries in\n    ",[57,1590,1591],{},"~/.claude"," and your OpenCode config get cleaned up properly.\n    See ",[41,1594,1041],{"to":197},"\n    for the complete list of files OpenPets touches.\n  ",{"title":244,"searchDepth":245,"depth":245,"links":1597},[1598,1599,1600,1601,1602,1603,1604],{"id":1220,"depth":245,"text":292},{"id":1256,"depth":245,"text":303},{"id":1317,"depth":245,"text":320},{"id":1381,"depth":245,"text":333},{"id":1470,"depth":245,"text":1474},{"id":1486,"depth":245,"text":1490},{"id":1510,"depth":245,"text":1514},"Download, install, launch, and uninstall OpenPets on macOS, Windows, and Linux.",{},30,{"title":117,"description":1605},"docs/install",[1611,1612,1613,1614,1615,1616,1617],{"id":1220,"label":292},{"id":1256,"label":303},{"id":1317,"label":320},{"id":1381,"label":333},{"id":1470,"label":1474},{"id":1486,"label":1490},{"id":1510,"label":1514},"Mj1QDoRq3mARx-BO0rvnvfMJfFOhQTvoGQIxI8curTU",{"id":1620,"title":1621,"body":1622,"description":1975,"extension":251,"meta":1976,"navTitle":1977,"navigation":253,"order":1978,"path":1979,"seo":1980,"stem":1981,"toc":1982,"__hash__":1990},"docs_en/docs/pets.md","Find and install pets",{"type":8,"value":1623,"toc":1966},[1624,1683,1722,1754,1804,1852,1883],[11,1625,16,1628,16,1632,16,1642,16,1645],{"id":1626,"className":1627},"gallery",[15],[18,1629,1631],{"id":1630},"browse-the-gallery","Browse the gallery",[22,1633,1634,1635,1638,1639,1641],{},"\n    The OpenPets pet catalog is published as a static JSON file at\n    ",[57,1636,1637],{},"https://openpets.dev/pets/catalog.v3.json",". The catalog page\n    at ",[374,1640,377],{"href":376}," renders that file as a\n    grid of installable pets, each with a preview spritesheet, name, and\n    short description.\n  ",[22,1643,1644],{},"\n    Each catalog entry is a small package containing:\n  ",[223,1646,69,1647,69,1653,69,1659,69,1665,69,1674,16],{},[226,1648,1649,1652],{},[32,1650,1651],{},"id"," — short slug (lowercase letters, digits, hyphens, underscores; up to 64 characters).",[226,1654,1655,1658],{},[32,1656,1657],{},"displayName"," — human-readable name (up to 120 characters).",[226,1660,1661,1664],{},[32,1662,1663],{},"description"," — short description (up to 500 characters).",[226,1666,1667,1670,1671,231],{},[32,1668,1669],{},"preview"," — HTTPS URL to a preview image on ",[57,1672,1673],{},"openpets.dev/pets/*",[226,1675,1676,1679,1680,231],{},[32,1677,1678],{},"zip"," — HTTPS URL to the downloadable package on ",[57,1681,1682],{},"zip.openpets.dev/pets/*",[11,1684,16,1687,16,1691,16,16,1700,16,1717],{"id":1685,"className":1686},"install-from-app",[15],[18,1688,1690],{"id":1689},"install-from-the-desktop-app","Install from the desktop app",[22,1692,1693,1694,1697,1698,378],{},"\n    This is the easiest path. Click the tray icon, open\n    ",[32,1695,1696],{},"Manage Pets...",", then pick a pet and click\n    ",[32,1699,386],{},[1261,1701,69,1702,69,1705,69,1711,69,1714,16],{},[226,1703,1704],{},"The desktop app fetches the catalog over HTTPS.",[226,1706,1707,1708,231],{},"It downloads the pet ZIP from ",[57,1709,1710],{},"zip.openpets.dev",[226,1712,1713],{},"It validates the ZIP and extracts it to your user data directory.",[226,1715,1716],{},"The pet appears in your installed list and can be set as the default.",[22,1718,354,1719,1721],{},[41,1720,1041],{"to":197},"\n    for the exact directory where installed pets live on each platform.\n  ",[11,1723,16,1726,16,1730,16,1733,16,1748,16,1751],{"id":1724,"className":1725},"install-from-cli",[15],[18,1727,1729],{"id":1728},"install-from-the-cli","Install from the CLI",[22,1731,1732],{},"\n    If the OpenPets desktop app is already running, you can install a pet\n    from a terminal:\n  ",[65,1734,69,1736,69,1743,16],{"className":1735},[485],[65,1737,1739,1741],{"className":1738},[489],[491,1740,1303],{},[491,1742,1306],{},[498,1744,1745],{},[57,1746,1747],{},"npx -y @open-pets/cli@latest install \u003Cpet-id>",[22,1749,1750],{},"\n    The CLI talks to the running app over local IPC and asks it to perform\n    the install. The desktop app does the actual download and validation;\n    the CLI just relays the request and prints the result.\n  ",[22,1752,1753],{},"\n    If the desktop app is not running, this command fails with a clear\n    message. Use the standalone installer below for an alternative that\n    works without the app.\n  ",[11,1755,16,1758,16,1761,16,1768,16,1783,16,1786],{"id":1756,"className":1757},"standalone-installer",[15],[18,1759,1760],{"id":1756},"Standalone installer",[22,1762,1763,1764,1767],{},"\n    For CI, dotfile bootstraps, or any environment where you cannot expect\n    the OpenPets desktop app to be running, use the standalone\n    ",[57,1765,1766],{},"install-pet"," package:\n  ",[65,1769,69,1771,69,1778,16],{"className":1770},[485],[65,1772,1774,1776],{"className":1773},[489],[491,1775,1303],{},[491,1777,1306],{},[498,1779,1780],{},[57,1781,1782],{},"npx -y install-pet \u003Cpet-id>",[22,1784,1785],{},"\n    The standalone installer prefers the running app when available and\n    falls back to a direct download otherwise. A direct install:\n  ",[223,1787,69,1788,69,1791,69,1794,69,1797,16],{},[226,1789,1790],{},"Acquires a per-user lock file under your user data directory so two installers cannot run at once.",[226,1792,1793],{},"Fetches the catalog and the pet ZIP over HTTPS.",[226,1795,1796],{},"Validates everything before writing — see safety limits below.",[226,1798,1799,1800,1803],{},"Extracts atomically into ",[57,1801,1802],{},"\u003CuserData>/pets/\u003Cpet-id>/"," and updates the OpenPets state file.",[11,1805,16,1808,16,1810,16,1817,16,1833,16,1849],{"id":1806,"className":1807},"local-codex-pets",[15],[18,1809,1020],{"id":1806},[22,1811,1812,1813,1816],{},"\n    If you are creating your own pets, you can drop them into\n    ",[57,1814,1815],{},"~/.codex/pets/"," and the desktop app picks them up\n    automatically — no catalog round-trip, no ZIP packaging.\n  ",[65,1818,69,1820,69,1828,16],{"className":1819},[485],[65,1821,1823,1826],{"className":1822},[489],[491,1824,1825],{},"Layout",[491,1827,496],{},[498,1829,1830],{},[57,1831,1832],{},"~/.codex/pets/\u003Cpet-id>/\n├── pet.json\n├── spritesheet.webp\n└── preview.webp   # optional",[22,1834,1835,1836,1838,1839,1842,1843,1845,1846,1848],{},"\n    The folder name must match the ",[57,1837,1651],{}," field in ",[57,1840,1841],{},"pet.json","\n    exactly. See ",[41,1844,176],{"to":175},"\n    for the full ",[57,1847,1841],{}," schema and size limits.\n  ",[22,1850,1851],{},"\n    Codex pets are intended for in-development testing. Once you are happy\n    with one, publish it to the gallery — see the pet submission template in\n    the OpenPets GitHub repo.\n  ",[11,1853,16,1856,16,1860,16,1866,16,1880],{"id":1854,"className":1855},"manage-pets",[15],[18,1857,1859],{"id":1858},"manage-installed-pets","Manage installed pets",[22,1861,1862,1863,1865],{},"\n    The ",[32,1864,371],{}," window lists every installed pet and\n    lets you:\n  ",[223,1867,69,1868,69,1871,69,1874,69,1877,16],{},[226,1869,1870],{},"Set a pet as the default (the one shown at startup, when enabled).",[226,1872,1873],{},"Show or hide the default pet from the tray.",[226,1875,1876],{},"Pause all pets (handy when you are presenting or recording).",[226,1878,1879],{},"Uninstall a pet you no longer want.",[22,1881,1882],{},"\n    The built-in pet cannot be uninstalled — it is the fallback OpenPets uses\n    if your selected default is missing or broken.\n  ",[11,1884,16,1887,16,1891,16,1894,16,1959],{"id":1885,"className":1886},"safety",[15],[18,1888,1890],{"id":1889},"safety-and-limits","Safety and limits",[22,1892,1893],{},"\n    Pet ZIPs are validated before anything is written to disk. The validation\n    is identical whether the install goes through the desktop app or the\n    standalone installer.\n  ",[65,1895,69,1897,16],{"className":1896},[68],[71,1898,73,1899,73,1909,69],{},[75,1900,77,1901,73],{},[79,1902,1903,1906],{},[82,1904,1905],{},"Limit",[82,1907,1908],{},"Value",[89,1910,77,1911,77,1919,77,1927,77,1935,77,1943,77,1951,73],{},[79,1912,1913,1916],{},[94,1914,1915],{},"Catalog file size",[94,1917,1918],{},"1 MB",[79,1920,1921,1924],{},[94,1922,1923],{},"ZIP download size",[94,1925,1926],{},"50 MB",[79,1928,1929,1932],{},[94,1930,1931],{},"Extracted total size",[94,1933,1934],{},"200 MB",[79,1936,1937,1940],{},[94,1938,1939],{},"File count per pet",[94,1941,1942],{},"500",[79,1944,1945,1948],{},[94,1946,1947],{},"Individual file size",[94,1949,1950],{},"100 MB",[79,1952,1953,1956],{},[94,1954,1955],{},"Fetch timeout",[94,1957,1958],{},"30 seconds",[22,1960,1961,1962,1965],{},"\n    On top of the size limits, the validator rejects symlinks, paths that\n    escape the pet directory, unsupported compression methods, encrypted\n    entries, and case-collision filenames. Pet ids that match the reserved\n    name ",[57,1963,1964],{},"builtin"," are rejected.\n  ",{"title":244,"searchDepth":245,"depth":245,"links":1967},[1968,1969,1970,1971,1972,1973,1974],{"id":1630,"depth":245,"text":1631},{"id":1689,"depth":245,"text":1690},{"id":1728,"depth":245,"text":1729},{"id":1756,"depth":245,"text":1760},{"id":1806,"depth":245,"text":1020},{"id":1858,"depth":245,"text":1859},{"id":1889,"depth":245,"text":1890},"Browse the OpenPets gallery, install pets from inside the app or from the CLI, manage your installed pets, and develop your own pets locally.",{},"Pets",40,"/docs/pets",{"title":1621,"description":1975},"docs/pets",[1983,1984,1985,1986,1987,1988,1989],{"id":1626,"label":1631},{"id":1685,"label":1690},{"id":1724,"label":1729},{"id":1756,"label":1760},{"id":1806,"label":1020},{"id":1854,"label":1859},{"id":1885,"label":1890},"ZukGvQjcgABRQXYZQOveamIuaGvanf1cWVMtxbUaGNQ",{"id":1992,"title":133,"body":1993,"description":2236,"extension":251,"meta":2237,"navTitle":2238,"navigation":253,"order":2239,"path":132,"seo":2240,"stem":2241,"toc":2242,"__hash__":2249},"docs_en/docs/ai-assistants.md",{"type":8,"value":1994,"toc":2228},[1995,2063,2119,2137,2152,2193],[11,1996,16,1999,16,2002,16,2005,16,2058],{"id":1997,"className":1998},"overview",[15],[18,2000,2001],{"id":1997},"Overview",[22,2003,2004],{},"\n    OpenPets connects to assistants through two layers:\n  ",[65,2006,69,2008,16],{"className":2007},[68],[71,2009,73,2010,73,2022,69],{},[75,2011,77,2012,73],{},[79,2013,2014,2017,2019],{},[82,2015,2016],{},"Layer",[82,2018,1338],{},[82,2020,2021],{},"Required?",[89,2023,77,2024,77,2045,73],{},[79,2025,300,2026,300,2031,300,2042,77],{},[94,2027,2028],{},[32,2029,2030],{},"MCP server",[94,2032,2033,2034,859,2036,2038,2039,2041],{},"Gives the assistant the ",[57,2035,508],{},[57,2037,512],{},", and ",[57,2040,515],{}," tools so it can drive the pet deliberately.",[94,2043,2044],{},"Yes — installed by every integration.",[79,2046,300,2047,300,2052,300,2055,77],{},[94,2048,2049],{},[32,2050,2051],{},"Lifecycle hooks",[94,2053,2054],{},"Hook into the assistant's lifecycle events so the pet reacts automatically when the assistant starts thinking, edits a file, runs a test, asks for permission, or finishes a task.",[94,2056,2057],{},"No — opt-in extra, Claude Code today.",[22,2059,2060,2061,378],{},"\n    Both layers go through the same local IPC and the same lease lifecycle\n    described in ",[41,2062,112],{"to":59},[11,2064,16,2067,16,2069,16,2083,16,2109],{"id":2065,"className":2066},"claude-code",[15],[18,2068,34],{"id":2065},[22,2070,2071,2072,2074,2075,2078,2079,2082],{},"\n    Open the desktop app's Integrations window and click ",[32,2073,386],{},"\n    on the Claude Code card. That installs the user-scope MCP server and\n    writes a small managed instructions file at ",[57,2076,2077],{},"~/.claude/openpets.md",",\n    imported from ",[57,2080,2081],{},"~/.claude/CLAUDE.md"," via a marker block.\n  ",[22,2084,2085,2086,2089,2090,863,2093,859,2096,859,2099,863,2102,859,2105,2108],{},"\n    Hooks are a separate opt-in action on the same card. They modify\n    ",[57,2087,2088],{},"~/.claude/settings.json"," to add OpenPets-managed command\n    entries for each Claude lifecycle event (",[57,2091,2092],{},"UserPromptSubmit",[57,2094,2095],{},"PreToolUse",[57,2097,2098],{},"PermissionRequest",[57,2100,2101],{},"Notification",[57,2103,2104],{},"Stop",[57,2106,2107],{},"StopFailure",").\n  ",[22,2110,2111,2112,2115,2116,378],{},"\n    For everything else — what the managed JSON looks like, how the hook\n    reaction map works, per-project setup with ",[57,2113,2114],{},"openpets configure",",\n    troubleshooting — see the dedicated\n    ",[41,2117,2118],{"to":543},"Claude Code integration page",[11,2120,16,2123,16,2125,16,2128,16,2131],{"id":2121,"className":2122},"opencode",[15],[18,2124,38],{"id":2121},[22,2126,2127],{},"\n    OpenCode integration adds three things to your OpenCode global config:\n    an OpenPets MCP entry, an OpenPets plugin reference, and a managed\n    instructions block.\n  ",[22,2129,2130],{},"\n    The OpenCode plugin hooks into the editor's event bus — chat messages,\n    tool execution events — and maps them to pet reactions, much like\n    Claude hooks do. Because it runs inside the OpenCode runtime, no\n    settings file changes are required beyond enabling the plugin in\n    config.\n  ",[22,2132,354,2133,2136],{},[41,2134,2135],{"to":550},"the OpenCode integration page","\n    for the global vs project setup details, the JSONC-aware config writes,\n    and how the managed instruction block looks.\n  ",[11,2138,16,2141,16,2144,16,2149],{"id":2139,"className":2140},"other-mcp-clients",[15],[18,2142,2143],{"id":2139},"Other MCP clients",[22,2145,2146,2147,378],{},"\n    Any assistant that supports stdio MCP servers can use OpenPets. Add the\n    OpenPets server to your client's MCP config — the exact command and JSON\n    examples are on ",[41,2148,154],{"to":43},[22,2150,2151],{},"\n    Cursor, VS Code (with the MCP plugin), Windsurf, Zed, and Claude\n    Desktop all work this way. Some clients require a restart after you add\n    the OpenPets entry; check your client's MCP setup notes if the tools do\n    not appear.\n  ",[11,2153,16,2156,16,2159,16,2166,16,2184],{"id":2154,"className":2155},"pet-routing",[15],[18,2157,2158],{"id":2154},"Pet routing",[22,2160,2161,2162,2165],{},"\n    By default, every assistant sends reactions and messages to the\n    OpenPets default pet — the one you chose as default in the tray menu.\n    If you want a specific assistant to drive a specific installed pet\n    instead, pass ",[57,2163,2164],{},"--pet \u003Cpet-id>"," to the MCP command.\n  ",[223,2167,69,2168,69,2175,69,2181,16],{},[226,2169,2170,2171,2174],{},"Without ",[57,2172,2173],{},"--pet",": everything routes to the default pet.",[226,2176,2177,2178,2180],{},"With ",[57,2179,2173],{},": a separate \"agent pet\" window opens while the assistant is active and closes when the assistant stops.",[226,2182,2183],{},"If the requested pet is missing, broken, or invalid, OpenPets routes events to the default pet instead and surfaces the fallback reason in status responses.",[22,2185,2186,2187,2189,2190,2192],{},"\n    The desktop app's Integrations card has a ",[32,2188,2158],{},"\n    selector that adds ",[57,2191,2173],{}," for you. If you wire up an MCP\n    client by hand, add the flag yourself.\n  ",[11,2194,16,2197,16,2201,16,2208,16,2211],{"id":2195,"className":2196},"removing",[15],[18,2198,2200],{"id":2199},"removing-integrations","Removing integrations",[22,2202,2203,2204,2207],{},"\n    Open the Integrations window and click ",[32,2205,2206],{},"Remove integration","\n    on the relevant card. That removes the OpenPets-managed MCP entry and\n    instructions file from your assistant's config.\n  ",[22,2209,2210],{},"\n    Hooks are removed separately from the same card because they live in a\n    different settings file. If you only want the automatic reactions to\n    stop, remove just the hooks; the MCP server stays installed.\n  ",[22,2212,2213,2214,2219,2220,2223,2224,2227],{},"\n    For project-local setups installed via\n    ",[41,2215,2217],{"to":2216},"/docs/cli#configure-command",[57,2218,2114],{},",\n    delete or rewrite the project's ",[57,2221,2222],{},".claude/settings.local.json","\n    or ",[57,2225,2226],{},".opencode/"," directory.\n  ",{"title":244,"searchDepth":245,"depth":245,"links":2229},[2230,2231,2232,2233,2234,2235],{"id":1997,"depth":245,"text":2001},{"id":2065,"depth":245,"text":34},{"id":2121,"depth":245,"text":38},{"id":2139,"depth":245,"text":2143},{"id":2154,"depth":245,"text":2158},{"id":2199,"depth":245,"text":2200},"Connect Claude Code, OpenCode, and other MCP-capable assistants to OpenPets. Overview of the integration layers and pet routing.",{},"AI assistants",50,{"title":133,"description":2236},"docs/ai-assistants",[2243,2244,2245,2246,2247,2248],{"id":1997,"label":2001},{"id":2065,"label":34},{"id":2121,"label":38},{"id":2139,"label":2143},{"id":2154,"label":2158},{"id":2195,"label":2200},"RwGWaYIPtQWj4O9LttgpUiZv8EoOjXQzhtvfVp8UTVI",{"id":2251,"title":165,"body":2252,"description":2905,"extension":251,"meta":2906,"navTitle":2907,"navigation":253,"order":2908,"path":164,"seo":2909,"stem":2910,"toc":2911,"__hash__":2919},"docs_en/docs/cli.md",{"type":8,"value":2253,"toc":2890},[2254,2400,2449,2688,2747,2797,2845],[11,2255,16,2257,16,2259,16,2264,16,2320,16,2331,16,2335,16,2353,16,2369,16,2390],{"id":1997,"className":2256},[15],[18,2258,2001],{"id":1997},[22,2260,1862,2261,2263],{},[57,2262,444],{}," CLI is the same code that ships inside the\n    desktop app, packaged so you can invoke it from a terminal too. It does\n    four things:\n  ",[65,2265,69,2267,16],{"className":2266},[68],[71,2268,73,2269,73,2279,69],{},[75,2270,77,2271,73],{},[79,2272,2273,2276],{},[82,2274,2275],{},"Command",[82,2277,2278],{},"Purpose",[89,2280,77,2281,77,2291,77,2300,77,2310,73],{},[79,2282,2283,2288],{},[94,2284,2285],{},[57,2286,2287],{},"openpets install \u003Cpet-id>",[94,2289,2290],{},"Install a pet through the running desktop app.",[79,2292,2293,2297],{},[94,2294,2295],{},[57,2296,2114],{},[94,2298,2299],{},"Set up Claude Code or OpenCode for a specific project.",[79,2301,2302,2307],{},[94,2303,2304],{},[57,2305,2306],{},"openpets mcp",[94,2308,2309],{},"Start the OpenPets MCP server (used by integrations).",[79,2311,2312,2317],{},[94,2313,2314],{},[57,2315,2316],{},"openpets hook",[94,2318,2319],{},"Run one Claude hook event from stdin (used by integrations).",[22,2321,2322,2323,60,2325,2327,2328,2330],{},"\n    You normally won't run ",[57,2324,2306],{},[57,2326,2316],{},"\n    yourself. They are the entry points the Claude Code and OpenCode\n    integrations write into your assistant's config when you click\n    ",[32,2329,386],{}," in the desktop app.\n  ",[826,2332,2334],{"id":2333},"how-to-invoke","How to invoke",[22,2336,2337,2338,2341,2342,2344,2345,2348,2349,2352],{},"\n    The CLI is published as ",[57,2339,2340],{},"@open-pets/cli"," on npm. There is no\n    separate installer — the desktop app does not put an ",[57,2343,444],{},"\n    binary on your ",[57,2346,2347],{},"PATH",". Invoke it with ",[57,2350,2351],{},"npx",":\n  ",[65,2354,69,2356,69,2364,16],{"className":2355},[485],[65,2357,2359,2362],{"className":2358},[489],[491,2360,2361],{},"Run a subcommand",[491,2363,1306],{},[498,2365,2366],{},[57,2367,2368],{},"npx -y @open-pets/cli@latest \u003Csubcommand> [...args]",[22,2370,2371,2372,2374,2375,2378,2379,2382,2383,2386,2387,2389],{},"\n    If you want a permanent ",[57,2373,444],{}," command, install the package\n    globally with ",[57,2376,2377],{},"npm install -g @open-pets/cli",". The bare\n    ",[57,2380,2381],{},"openpets ..."," syntax used in the Usage blocks below describes\n    the subcommand shape; substitute ",[57,2384,2385],{},"npx -y @open-pets/cli@latest","\n    for ",[57,2388,444],{}," if you haven't installed it globally.\n  ",[22,2391,2392,2393,60,2396,2399],{},"\n    Run any subcommand with ",[57,2394,2395],{},"-h",[57,2397,2398],{},"--help"," for a\n    summary.\n  ",[11,2401,16,2404,16,2410,16,2413,16,2428],{"id":2402,"className":2403},"install-command",[15],[18,2405,2407],{"id":2406},"openpets-install",[57,2408,2409],{},"openpets install",[22,2411,2412],{},"\n    Installs a pet from the OpenPets catalog by sending the request to the\n    running desktop app over local IPC. The desktop app downloads the pet\n    ZIP, validates it, and adds it to your installed pets.\n  ",[65,2414,69,2416,69,2424,16],{"className":2415},[485],[65,2417,2419,2422],{"className":2418},[489],[491,2420,2421],{},"Usage",[491,2423,1306],{},[498,2425,2426],{},[57,2427,2287],{},[223,2429,69,2430,69,2439,69,2446,16],{},[226,2431,2432,2435,2436,2438],{},[57,2433,2434],{},"\u003Cpet-id>"," must match the pet id regex (lowercase letters, digits, hyphens, underscores; 1–64 characters; cannot be ",[57,2437,1964],{},").",[226,2440,2441,2442,2445],{},"The OpenPets desktop app must be running. If it is not, the install fails — use the standalone ",[374,2443,1766],{"href":2444},"https://www.npmjs.com/package/install-pet"," package for a direct download path that does not require the app.",[226,2447,2448],{},"Install requests use a longer 60-second response timeout to accommodate larger pet downloads.",[11,2450,16,2453,16,2458,16,2469,16,2484,16,2488,16,2593,16,2597,16,2604,16,2633,16,2637,16,2653,16,2656,16,2659],{"id":2451,"className":2452},"configure-command",[15],[18,2454,2456],{"id":2455},"openpets-configure",[57,2457,2114],{},[22,2459,2460,2461,2465,2466,2468],{},"\n    Sets up an AI assistant ",[2462,2463,2464],"em",{},"for a specific project",". This is different\n    from the user-scope install you get from the desktop app's Integrations\n    window: ",[57,2467,2114],{}," writes project-local config so the\n    setup ships with the repository.\n  ",[65,2470,69,2472,69,2479,16],{"className":2471},[485],[65,2473,2475,2477],{"className":2474},[489],[491,2476,2421],{},[491,2478,1306],{},[498,2480,2481],{},[57,2482,2483],{},"openpets configure [--agent claude|opencode] [--pet \u003Cid>] [--cwd \u003Cpath>]\n                  [--yes] [--force] [--local-dev]",[826,2485,2487],{"id":2486},"options","Options",[65,2489,69,2491,16],{"className":2490},[68],[71,2492,73,2493,73,2503,69],{},[75,2494,77,2495,73],{},[79,2496,2497,2500],{},[82,2498,2499],{},"Flag",[82,2501,2502],{},"Description",[89,2504,77,2505,77,2523,77,2533,77,2543,77,2556,77,2569,77,2582,73],{},[79,2506,2507,2512],{},[94,2508,2509],{},[57,2510,2511],{},"--agent \u003Cagent>",[94,2513,2514,2515,60,2518,2520,2521,231],{},"Which assistant to configure: ",[57,2516,2517],{},"claude",[57,2519,2121],{},". Defaults to ",[57,2522,2517],{},[79,2524,2525,2530],{},[94,2526,2527],{},[57,2528,2529],{},"--pet \u003Cid>",[94,2531,2532],{},"Pet id to target. If omitted, the CLI prompts you with the list of installed pets (interactive shells only).",[79,2534,2535,2540],{},[94,2536,2537],{},[57,2538,2539],{},"--cwd \u003Cpath>",[94,2541,2542],{},"Project directory to configure. Defaults to the current directory.",[79,2544,2545,2553],{},[94,2546,2547,859,2550],{},[57,2548,2549],{},"--yes",[57,2551,2552],{},"-y",[94,2554,2555],{},"Accepted for scripts; no confirmation prompt is shown.",[79,2557,2558,2566],{},[94,2559,2560,859,2563],{},[57,2561,2562],{},"--force",[57,2564,2565],{},"--replace",[94,2567,2568],{},"Replace any existing OpenPets-managed entries for this project, instead of leaving them alone.",[79,2570,2571,2576],{},[94,2572,2573],{},[57,2574,2575],{},"--local-dev",[94,2577,2578,2579,2581],{},"Use local development command paths instead of the published ",[57,2580,2351],{}," command. Useful when working on OpenPets itself.",[79,2583,2584,2590],{},[94,2585,2586,859,2588],{},[57,2587,2395],{},[57,2589,2398],{},[94,2591,2592],{},"Show command help.",[826,2594,2596],{"id":2595},"what-configure-writes","What configure writes",[22,2598,2599,2600,2603],{},"For ",[32,2601,2602],{},"Claude"," projects:",[223,2605,69,2606,69,2615,69,2622,16],{},[226,2607,2608,2609,2611,2612,231],{},"An ",[57,2610,444],{}," MCP entry at project scope, added via ",[57,2613,2614],{},"claude mcp add-json",[226,2616,2617,2618,2621],{},"OpenPets-managed hook entries in ",[57,2619,2620],{},"\u003Cproject>/.claude/settings.local.json"," for all Claude lifecycle events.",[226,2623,2624,2625,2628,2629,2632],{},"Hook commands include the ",[57,2626,2627],{},"--openpets-managed"," marker and the ",[57,2630,2631],{},"--project-local"," flag.",[22,2634,2599,2635,2603],{},[32,2636,38],{},[223,2638,69,2639,69,2644,69,2647,16],{},[226,2640,2608,2641,2643],{},[57,2642,444],{}," MCP entry in the project's OpenCode config.",[226,2645,2646],{},"An OpenPets plugin reference.",[226,2648,2649,2650,2652],{},"A managed instructions file under the project's ",[57,2651,2226],{}," directory.",[22,2654,2655],{},"\n    The OpenCode setup is committable — you can check it into your repo and\n    teammates get OpenPets in that project automatically once they have the\n    desktop app installed.\n  ",[826,2657,2658],{"id":1885},"Safety",[223,2660,69,2661,69,2664,69,2673,69,2678,16],{},[226,2662,2663],{},"The project directory cannot be a symlink and must be a real directory.",[226,2665,2666,2667,60,2670,2672],{},"If ",[57,2668,2669],{},".claude",[57,2671,2222],{}," exists, they cannot be symlinks and must stay within the project root.",[226,2674,2675,2676,231],{},"Settings files are written atomically (temp file plus rename) with permissions ",[57,2677,819],{},[226,2679,2680,2681,2683,2684,2687],{},"Claude must be on ",[57,2682,2347],{}," — the CLI calls ",[57,2685,2686],{},"claude --version"," before doing anything.",[11,2689,16,2692,16,2697,16,2704,16,2719,16,2742],{"id":2690,"className":2691},"mcp-command",[15],[18,2693,2695],{"id":2694},"openpets-mcp",[57,2696,2306],{},[22,2698,2699,2700,2703],{},"\n    Starts the OpenPets MCP server. The CLI spawns the\n    ",[57,2701,2702],{},"@open-pets/mcp"," entry as a child process with stdio\n    forwarded, so the MCP client (Claude Code, Cursor, etc.) talks to it\n    directly through stdin and stdout.\n  ",[65,2705,69,2707,69,2714,16],{"className":2706},[485],[65,2708,2710,2712],{"className":2709},[489],[491,2711,2421],{},[491,2713,1306],{},[498,2715,2716],{},[57,2717,2718],{},"openpets mcp [--pet \u003Cid>]",[223,2720,69,2721,69,2726,69,2733,16],{},[226,2722,2723,2725],{},[57,2724,2529],{}," targets a specific installed pet. Without it, events go to the default pet.",[226,2727,2728,2729,2732],{},"You normally don't run this yourself. The Integrations setup writes a command that effectively runs ",[57,2730,2731],{},"openpets mcp --pet \u003Cid>"," into your assistant's MCP config.",[226,2734,2735,2736,60,2739,231],{},"The server acquires a lease on startup, heartbeats every 5 seconds, and releases it on ",[57,2737,2738],{},"SIGINT",[57,2740,2741],{},"SIGTERM",[22,2743,354,2744,2746],{},[41,2745,154],{"to":43}," for the\n    complete tool surface, schemas, and integration with other MCP clients.\n  ",[11,2748,16,2751,16,2756,16,2759,16,2774],{"id":2749,"className":2750},"hook-command",[15],[18,2752,2754],{"id":2753},"openpets-hook",[57,2755,2316],{},[22,2757,2758],{},"\n    Runs a single Claude Code hook event. Claude pipes one JSON event to\n    stdin and waits for the command to exit; OpenPets reads the event,\n    decides on a reaction or short message, and exits quietly.\n  ",[65,2760,69,2762,69,2769,16],{"className":2761},[485],[65,2763,2765,2767],{"className":2764},[489],[491,2766,2421],{},[491,2768,1306],{},[498,2770,2771],{},[57,2772,2773],{},"openpets hook --openpets-managed [--project-local] [--pet \u003Cid>]",[223,2775,69,2776,69,2781,69,2789,69,2794,16],{},[226,2777,2778,2780],{},[57,2779,2627],{}," is a marker the CLI looks for when uninstalling or replacing hooks. It must be present on every OpenPets hook entry.",[226,2782,2783,2785,2786,2788],{},[57,2784,2631],{}," signals that this hook was installed at project scope (in ",[57,2787,2222],{},"). Project-local hooks are tracked separately so user-scope hooks can skip events that the project already handled.",[226,2790,2791,2793],{},[57,2792,2529],{}," targets a specific pet.",[226,2795,2796],{},"The hook command never prints to stdout (so Claude does not accidentally ingest it as context) and always exits with code 0 unless OpenPets itself is misconfigured. If the desktop app is closed, the hook exits successfully and silently.",[11,2798,16,2801,16,2804,16,2840],{"id":2799,"className":2800},"exit-codes",[15],[18,2802,2803],{"id":2799},"Exit codes",[65,2805,69,2807,16],{"className":2806},[68],[71,2808,73,2809,73,2819,69],{},[75,2810,77,2811,73],{},[79,2812,2813,2816],{},[82,2814,2815],{},"Code",[82,2817,2818],{},"Meaning",[89,2820,77,2821,77,2831,73],{},[79,2822,2823,2828],{},[94,2824,2825],{},[57,2826,2827],{},"0",[94,2829,2830],{},"Success.",[79,2832,2833,2837],{},[94,2834,2835],{},[57,2836,837],{},[94,2838,2839],{},"Usage error, configuration error, or unexpected failure. The CLI prints the error message to stderr.",[22,2841,69,2842,2844],{},[57,2843,2316],{}," is the deliberate exception: it tries hard to\n    exit 0 even when the desktop app is unavailable, so Claude sessions are\n    never blocked by an OpenPets problem.\n  ",[11,2846,16,2849,16,2853],{"id":2847,"className":2848},"env-vars",[15],[18,2850,2852],{"id":2851},"environment-variables","Environment variables",[65,2854,69,2856,16],{"className":2855},[68],[71,2857,73,2858,73,2868,69],{},[75,2859,77,2860,73],{},[79,2861,2862,2865],{},[82,2863,2864],{},"Variable",[82,2866,2867],{},"Effect",[89,2869,77,2870,77,2880,73],{},[79,2871,300,2872,300,2877,77],{},[94,2873,2874],{},[57,2875,2876],{},"OPENPETS_DEBUG=1",[94,2878,2879],{},"Enables verbose debug logging from the hook command. Useful when diagnosing why hooks are not reaching the pet.",[79,2881,300,2882,300,2887,77],{},[94,2883,2884],{},[57,2885,2886],{},"OPENPETS_DISCOVERY_FILE",[94,2888,2889],{},"Overrides the default discovery-file path. Useful for tests, or when running OpenPets with a non-standard runtime directory.",{"title":244,"searchDepth":245,"depth":245,"links":2891},[2892,2895,2896,2901,2902,2903,2904],{"id":1997,"depth":245,"text":2001,"children":2893},[2894],{"id":2333,"depth":1196,"text":2334},{"id":2406,"depth":245,"text":2409},{"id":2455,"depth":245,"text":2114,"children":2897},[2898,2899,2900],{"id":2486,"depth":1196,"text":2487},{"id":2595,"depth":1196,"text":2596},{"id":1885,"depth":1196,"text":2658},{"id":2694,"depth":245,"text":2306},{"id":2753,"depth":245,"text":2316},{"id":2799,"depth":245,"text":2803},{"id":2851,"depth":245,"text":2852},"Every command, flag, and exit code in the openpets CLI — install pets, configure projects, run the MCP server, and handle Claude hooks.",{},"CLI",60,{"title":165,"description":2905},"docs/cli",[2912,2913,2914,2915,2916,2917,2918],{"id":1997,"label":2001},{"id":2402,"label":2409},{"id":2451,"label":2114},{"id":2690,"label":2306},{"id":2749,"label":2316},{"id":2799,"label":2803},{"id":2847,"label":2852},"npeBwc0DCgngcGZfjkTKr38z5GaxhqlAEieH2Xh1m4Y",{"id":2921,"title":154,"body":2922,"description":3644,"extension":251,"meta":3645,"navTitle":3646,"navigation":253,"order":3647,"path":43,"seo":3648,"stem":3649,"toc":3650,"__hash__":3664},"docs_en/docs/mcp.md",{"type":8,"value":2923,"toc":3616},[2924,2951,2990,3110,3188,3301,3393,3468,3514,3546],[11,2925,16,2927,16,2929,16,2932,16,2935],{"id":1997,"className":2926},[15],[18,2928,2001],{"id":1997},[22,2930,2931],{},"\n    OpenPets ships a Model Context Protocol (MCP) server that lets any\n    MCP-capable assistant drive your desktop pet. It is a small,\n    purpose-built surface: check status, change the pet's reaction, show a\n    short message. Nothing else.\n  ",[22,2933,2934],{},"\n    The server runs as a local stdio process. Your MCP client launches it,\n    pipes JSON-RPC over stdin/stdout, and OpenPets forwards the requests to\n    the desktop app over local IPC.\n  ",[65,2936,69,2938,69,2946,16],{"className":2937},[485],[65,2939,2941,2944],{"className":2940},[489],[491,2942,2943],{},"Runtime path",[491,2945,496],{},[498,2947,2948],{},[57,2949,2950],{},"MCP client (Claude, Cursor, Zed, ...)\n  -> stdio\n  -> @open-pets/mcp server\n  -> @open-pets/client (token-stamped local IPC)\n  -> OpenPets desktop app\n  -> default pet or leased agent pet",[11,2952,16,2955,16,2958,16,2961,16,2964,16,2980],{"id":2953,"className":2954},"quick-install",[15],[18,2956,2957],{"id":2953},"Quick install",[22,2959,2960],{},"\n    If your assistant has a dedicated OpenPets integration card (Claude Code\n    or OpenCode today), use that — it writes the correct command for your\n    install method and handles the managed instructions for you. Otherwise\n    add OpenPets to your client manually as a stdio MCP server.\n  ",[22,2962,2963],{},"\n    For Claude Code specifically:\n  ",[65,2965,69,2967,69,2975,16],{"className":2966},[485],[65,2968,2970,2973],{"className":2969},[489],[491,2971,2972],{},"Claude MCP (user scope)",[491,2974,1306],{},[498,2976,2977],{},[57,2978,2979],{},"claude mcp add --scope user openpets -- npx -y @open-pets/mcp@latest",[22,2981,2982,2983,2985,2986,2989],{},"\n    Add ",[57,2984,2164],{}," after ",[57,2987,2988],{},"@open-pets/mcp@latest"," if\n    you want to target a specific installed pet.\n  ",[11,2991,16,2994,16,2997,16,3003,16,3007,16,3022,16,3026,16,3029,16,3045,16,3049,16,3107],{"id":2992,"className":2993},"server-command",[15],[18,2995,2996],{"id":2992},"Server command",[22,2998,2999,3000,3002],{},"\n    The server binary is published as ",[57,3001,2702],{}," on npm and\n    is also bundled inside the desktop app. There are two command shapes\n    depending on whether you are using the published package or the bundled\n    one inside an OpenPets release.\n  ",[826,3004,3006],{"id":3005},"published-package","Published package",[65,3008,69,3010,69,3017,16],{"className":3009},[485],[65,3011,3013,3015],{"className":3012},[489],[491,3014,2275],{},[491,3016,1306],{},[498,3018,3019],{},[57,3020,3021],{},"npx -y @open-pets/mcp@latest [--pet \u003Cpet-id>]",[826,3023,3025],{"id":3024},"bundled-inside-the-desktop-app","Bundled inside the desktop app",[22,3027,3028],{},"\n    The OpenPets Integrations window writes a path-based command that points\n    inside the installed app bundle, so it works without internet access\n    after installation. On macOS the command looks like:\n  ",[65,3030,69,3032,69,3040,16],{"className":3031},[485],[65,3033,3035,3038],{"className":3034},[489],[491,3036,3037],{},"macOS bundled command",[491,3039,1306],{},[498,3041,3042],{},[57,3043,3044],{},"node /Applications/OpenPets.app/Contents/Resources/app.asar.unpacked/node_modules/@open-pets/mcp/dist/index.js",[826,3046,3048],{"id":3047},"flags","Flags",[65,3050,69,3052,16],{"className":3051},[68],[71,3053,73,3054,73,3062,69],{},[75,3055,77,3056,73],{},[79,3057,3058,3060],{},[82,3059,2499],{},[82,3061,2818],{},[89,3063,77,3064,77,3073,77,3083,77,3094,73],{},[79,3065,3066,3070],{},[94,3067,3068],{},[57,3069,2164],{},[94,3071,3072],{},"Request a specific installed pet for this MCP process. Missing pets fall back to the default.",[79,3074,3075,3080],{},[94,3076,3077],{},[57,3078,3079],{},"--pet=\u003Cpet-id>",[94,3081,3082],{},"Same as above with the equals form.",[79,3084,3085,3091],{},[94,3086,3087,859,3089],{},[57,3088,2398],{},[57,3090,2395],{},[94,3092,3093],{},"Show help and exit.",[79,3095,3096,3104],{},[94,3097,3098,859,3101],{},[57,3099,3100],{},"--version",[57,3102,3103],{},"-v",[94,3105,3106],{},"Print the package version and exit.",[22,3108,3109],{},"\n    Pet ids are limited to 128 bytes UTF-8 and cannot contain control\n    characters, slashes, or backslashes. The id must also match the standard\n    pet id regex (lowercase letters, digits, hyphens, underscores).\n  ",[11,3111,16,3114,16,3117,16,3123,16,3125,16,3142,16,3146,16,3162,16,3166,16,3172],{"id":3112,"className":3113},"client-config-examples",[15],[18,3115,3116],{"id":3112},"Client config examples",[22,3118,3119,3120,3122],{},"\n    The JSON snippets below show the OpenPets MCP entry for several popular\n    clients. Replace ",[57,3121,2434],{}," with the pet you want, or\n    omit the flag to target the default pet.\n  ",[826,3124,34],{"id":2065},[65,3126,69,3128,69,3137,16],{"className":3127},[485],[65,3129,3131,3134],{"className":3130},[489],[491,3132,3133],{},"~/.claude/mcp.json (excerpt)",[491,3135,3136],{},"json",[498,3138,3139],{},[57,3140,3141],{},"{\n  \"mcpServers\": {\n    \"openpets\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@open-pets/mcp\", \"--pet\", \"\u003Cpet-id>\"]\n    }\n  }\n}",[826,3143,3145],{"id":3144},"cursor-windsurf-generic-stdio-mcp","Cursor, Windsurf, generic stdio MCP",[65,3147,69,3149,69,3157,16],{"className":3148},[485],[65,3150,3152,3155],{"className":3151},[489],[491,3153,3154],{},"mcp.json",[491,3156,3136],{},[498,3158,3159],{},[57,3160,3161],{},"{\n  \"mcpServers\": {\n    \"openpets\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@open-pets/mcp\"]\n    }\n  }\n}",[826,3163,3165],{"id":3164},"bundled-app-path","Bundled-app path",[22,3167,3168,3169,3171],{},"\n    Use this when you want to skip ",[57,3170,2351],{}," and run the MCP server\n    that ships inside an installed OpenPets desktop app.\n  ",[65,3173,69,3175,69,3183,16],{"className":3174},[485],[65,3176,3178,3181],{"className":3177},[489],[491,3179,3180],{},"mcp.json (bundled)",[491,3182,3136],{},[498,3184,3185],{},[57,3186,3187],{},"{\n  \"mcpServers\": {\n    \"openpets\": {\n      \"type\": \"stdio\",\n      \"command\": \"node\",\n      \"args\": [\n        \"/Applications/OpenPets.app/Contents/Resources/app.asar.unpacked/node_modules/@open-pets/mcp/dist/index.js\"\n      ]\n    }\n  }\n}",[11,3189,16,3192,16,3195,16,3198,16,3252,16,3256,16,3271,16,3286],{"id":3190,"className":3191},"tools",[15],[18,3193,3194],{"id":3190},"Tools",[22,3196,3197],{},"\n    The server registers three tools. Their input schemas are enforced\n    server-side with zod; invalid input returns a tool error without\n    contacting the desktop app.\n  ",[65,3199,69,3201,16],{"className":3200},[68],[71,3202,73,3203,73,3215,69],{},[75,3204,77,3205,73],{},[79,3206,3207,3210,3212],{},[82,3208,3209],{},"Tool",[82,3211,2278],{},[82,3213,3214],{},"Annotations",[89,3216,77,3217,77,3229,77,3241,73],{},[79,3218,3219,3223,3226],{},[94,3220,3221],{},[57,3222,508],{},[94,3224,3225],{},"Check whether OpenPets is reachable, which pet is currently targeted, and whether the lease is healthy.",[94,3227,3228],{},"read-only, idempotent",[79,3230,3231,3235,3238],{},[94,3232,3233],{},[57,3234,512],{},[94,3236,3237],{},"Set a short coding-oriented reaction on the targeted pet.",[94,3239,3240],{},"side-effects, non-idempotent",[79,3242,3243,3247,3250],{},[94,3244,3245],{},[57,3246,515],{},[94,3248,3249],{},"Show a short safe message on the targeted pet (with optional reaction).",[94,3251,3240],{},[826,3253,3255],{"id":3254},"input-schemas","Input schemas",[65,3257,69,3259,69,3266,16],{"className":3258},[485],[65,3260,3262,3264],{"className":3261},[489],[491,3263,508],{},[491,3265,3136],{},[498,3267,3268],{},[57,3269,3270],{},"{}",[65,3272,69,3274,69,3281,16],{"className":3273},[485],[65,3275,3277,3279],{"className":3276},[489],[491,3278,512],{},[491,3280,3136],{},[498,3282,3283],{},[57,3284,3285],{},"{\n  \"reaction\": \"thinking\"\n}",[65,3287,69,3289,69,3296,16],{"className":3288},[485],[65,3290,3292,3294],{"className":3291},[489],[491,3293,515],{},[491,3295,3136],{},[498,3297,3298],{},[57,3299,3300],{},"{\n  \"message\": \"Building the pet manager\",\n  \"reaction\": \"working\"\n}",[11,3302,16,3305,16,3308,16,3337,16,3343,16,3390],{"id":3303,"className":3304},"reactions-and-speech",[15],[18,3306,3307],{"id":3303},"Reactions and speech",[22,3309,3310,3311,3314,3315,859,3317,863,3319,859,3321,859,3323,863,3325,859,3327,859,3329,863,3331,859,3333,2038,3335,378],{},"\n    Reactions are picked from a closed list. See\n    ",[41,3312,1048],{"to":3313},"/docs/concepts#reactions"," for the full\n    table; the allowed values are ",[57,3316,1080],{},[57,3318,1090],{},[57,3320,1100],{},[57,3322,1110],{},[57,3324,1120],{},[57,3326,1130],{},[57,3328,1140],{},[57,3330,1150],{},[57,3332,1160],{},[57,3334,1170],{},[57,3336,1180],{},[22,3338,3339,3340,3342],{},"\n    Speech messages are short. The server enforces these rules on every\n    ",[57,3341,515],{}," call:\n  ",[223,3344,69,3345,69,3348,69,3351,69,3367,69,3374,16],{},[226,3346,3347],{},"1 to 140 characters after trimming.",[226,3349,3350],{},"Single line — carriage returns and newlines are rejected.",[226,3352,3353,3354,3357,3358,859,3361,859,3364,2438],{},"No code-like patterns (backticks, ",[57,3355,3356],{},"\u003Cscript",", function definitions, JS keywords like ",[57,3359,3360],{},"class",[57,3362,3363],{},"import",[57,3365,3366],{},"const",[226,3368,3369,3370,3373],{},"No URLs or file paths (HTTP URLs, ",[57,3371,3372],{},"www.",", slash paths, Windows drive letters).",[226,3375,3376,3377,859,3380,859,3383,859,3386,3389],{},"No secret-like text (",[57,3378,3379],{},"api_key",[57,3381,3382],{},"secret",[57,3384,3385],{},"token",[57,3387,3388],{},"password",", PEM headers).",[22,3391,3392],{},"\n    Reject reasons come back as plain text tool errors. The pet never\n    receives anything that fails validation.\n  ",[11,3394,16,3397,16,3400,16,3403],{"id":3395,"className":3396},"validation-and-safety",[15],[18,3398,3399],{"id":3395},"Validation and safety",[22,3401,3402],{},"\n    The MCP server is built to be a benign visible-status channel. It\n    intentionally cannot read your editor state, your project files, or your\n    assistant's transcript.\n  ",[65,3404,69,3406,16],{"className":3405},[68],[71,3407,73,3408,73,3418,69],{},[75,3409,77,3410,73],{},[79,3411,3412,3415],{},[82,3413,3414],{},"Protection",[82,3416,3417],{},"How it works",[89,3419,77,3420,77,3431,77,3444,77,3452,77,3460,73],{},[79,3421,300,3422,300,3425,77],{},[94,3423,3424],{},"Server instructions",[94,3426,3427,3428,3430],{},"The MCP server tells the assistant to use ",[57,3429,515],{}," only for short user-facing status messages.",[79,3432,300,3433,300,3436,77],{},[94,3434,3435],{},"Schema validation",[94,3437,3438,3439,35,3441,3443],{},"Every ",[57,3440,512],{},[57,3442,515],{}," input is validated with zod before leaving the server.",[79,3445,300,3446,300,3449,77],{},[94,3447,3448],{},"Speech validation",[94,3450,3451],{},"Messages that look like code, URLs, paths, or secrets are rejected before reaching the desktop app.",[79,3453,300,3454,300,3457,77],{},[94,3455,3456],{},"Error sanitization",[94,3458,3459],{},"Low-level errors (IPC paths, socket names, tokens, system error codes) are stripped from tool-error responses. The MCP client sees a short \"OpenPets desktop app or local IPC is unavailable\" message instead of internals.",[79,3461,300,3462,300,3465,77],{},[94,3463,3464],{},"No network",[94,3466,3467],{},"The MCP server itself only talks to the desktop app over a local socket; it never reaches the network.",[11,3469,16,3472,16,3475,16,3482,16,3507],{"id":3470,"className":3471},"pet-targeting-and-leases",[15],[18,3473,3474],{"id":3470},"Pet targeting and leases",[22,3476,3477,3478,3481],{},"\n    Pet targeting works through leases. See\n    ",[41,3479,659],{"to":3480},"/docs/concepts#leases-and-routing","\n    for the underlying lifecycle. Inside the MCP server it works like this:\n  ",[1261,3483,69,3484,69,3490,69,3493,69,3496,69,3499,16],{},[226,3485,3486,3487,3489],{},"The server acquires a lease at startup, passing the optional ",[57,3488,2529],{}," as the requested pet.",[226,3491,3492],{},"The desktop app picks an actual pet — the requested one if it is installed and usable, otherwise the default pet, with a fallback reason attached.",[226,3494,3495],{},"Every reaction and message includes the lease id, so events route to the leased pet even when the default pet is also visible.",[226,3497,3498],{},"The server heartbeats every 5 seconds; if a heartbeat fails, the lease is marked degraded and tool calls return a clear \"lease unavailable\" error.",[226,3500,3501,3502,60,3504,3506],{},"On ",[57,3503,2738],{},[57,3505,2741],{},", the server releases the lease before shutting down.",[22,3508,3509,3510,3513],{},"\n    If the requested pet is missing, broken, or invalid, the lease is still\n    granted but it points at the default pet. The structured status response\n    surfaces this through ",[57,3511,3512],{},"fallbackReason"," so a careful assistant\n    can warn the user.\n  ",[11,3515,16,3518,16,3521,16,3528,16,3531],{"id":3516,"className":3517},"ipc-discovery",[15],[18,3519,3520],{"id":3516},"IPC discovery",[22,3522,3523,3524,3527],{},"\n    The MCP server uses the standard OpenPets discovery file to find the\n    desktop app. See ",[41,3525,756],{"to":3526},"/docs/concepts#local-ipc","\n    for the file format and per-platform paths.\n  ",[22,3529,3530],{},"\n    Two things to be aware of when running the MCP server in unusual\n    environments:\n  ",[223,3532,69,3533,69,3540,16],{},[226,3534,3535,3536,3539],{},"The discovery file's ",[57,3537,3538],{},"platform"," field must match the platform of the MCP process. Running the macOS-built MCP server from a Linux VM against a macOS-built desktop app will fail discovery validation.",[226,3541,3542,3543,3545],{},"Set ",[57,3544,2886],{}," to override the discovery path — useful when the OpenPets desktop app is running for a different user, or when scripting tests.",[11,3547,16,3550,16,3552,16,3556,16,3567,16,3571,16,3579,16,3583,16,3597,16,3603,16,3611],{"id":3548,"className":3549},"troubleshooting",[15],[18,3551,214],{"id":3548},[826,3553,3555],{"id":3554},"the-mcp-server-starts-but-every-tool-returns-openpets-is-unavailable","The MCP server starts but every tool returns \"OpenPets is unavailable\"",[223,3557,69,3558,69,3561,69,3564,16],{},[226,3559,3560],{},"Make sure the OpenPets desktop app is running.",[226,3562,3563],{},"Check that the discovery file exists at the expected path for your platform.",[226,3565,3566],{},"If you restarted the desktop app, the discovery token rotated. Restart the MCP client too so it picks up the new lease.",[826,3568,3570],{"id":3569},"tools-return-openpets-lease-is-unavailable","Tools return \"OpenPets lease is unavailable\"",[223,3572,69,3573,69,3576,16],{},[226,3574,3575],{},"The startup lease failed or expired. Most often this means the desktop app was not running when the MCP server started.",[226,3577,3578],{},"Restart the MCP client. The server tries to re-acquire a lease on startup.",[826,3580,3582],{"id":3581},"the-pet-does-not-change-reaction-even-though-calls-succeed","The pet does not change reaction even though calls \"succeed\"",[223,3584,69,3585,69,3588,16],{},[226,3586,3587],{},"Check whether the default pet is paused from the tray menu. Paused pets accept reactions silently.",[226,3589,3590,3591,3593,3594,3596],{},"If you passed ",[57,3592,2529],{}," and the structured status shows a ",[57,3595,3512],{},", the requested pet is missing or broken — reinstall it.",[826,3598,3600,3602],{"id":3599},"openpets_say-messages-get-rejected",[57,3601,515],{}," messages get rejected",[223,3604,69,3605,69,3608,16],{},[226,3606,3607],{},"The validation is strict for safety. Remove code-looking content, URLs, paths, or secret-like words and try again.",[226,3609,3610],{},"If you are sending a stack trace, error log, or file path through the pet, do not. Use a separate channel.",[22,3612,354,3613,3615],{},[41,3614,214],{"to":213}," for\n    broader symptoms that are not specific to the MCP path.\n  ",{"title":244,"searchDepth":245,"depth":245,"links":3617},[3618,3619,3620,3625,3630,3633,3634,3635,3636,3637],{"id":1997,"depth":245,"text":2001},{"id":2953,"depth":245,"text":2957},{"id":2992,"depth":245,"text":2996,"children":3621},[3622,3623,3624],{"id":3005,"depth":1196,"text":3006},{"id":3024,"depth":1196,"text":3025},{"id":3047,"depth":1196,"text":3048},{"id":3112,"depth":245,"text":3116,"children":3626},[3627,3628,3629],{"id":2065,"depth":1196,"text":34},{"id":3144,"depth":1196,"text":3145},{"id":3164,"depth":1196,"text":3165},{"id":3190,"depth":245,"text":3194,"children":3631},[3632],{"id":3254,"depth":1196,"text":3255},{"id":3303,"depth":245,"text":3307},{"id":3395,"depth":245,"text":3399},{"id":3470,"depth":245,"text":3474},{"id":3516,"depth":245,"text":3520},{"id":3548,"depth":245,"text":214,"children":3638},[3639,3640,3641,3642],{"id":3554,"depth":1196,"text":3555},{"id":3569,"depth":1196,"text":3570},{"id":3581,"depth":1196,"text":3582},{"id":3599,"depth":1196,"text":3643},"openpets_say messages get rejected","How to connect any MCP-capable assistant to OpenPets — server command, tools, schemas, safety rules, pet targeting, and troubleshooting.",{},"MCP",70,{"title":154,"description":3644},"docs/mcp",[3651,3652,3653,3654,3655,3656,3658,3660,3662,3663],{"id":1997,"label":2001},{"id":2953,"label":2957},{"id":2992,"label":2996},{"id":3112,"label":3116},{"id":3190,"label":3194},{"id":3303,"label":3657},"Reactions & speech",{"id":3395,"label":3659},"Validation & safety",{"id":3470,"label":3661},"Pet targeting & leases",{"id":3516,"label":3520},{"id":3548,"label":214},"xjvtJpQCAqS8ISBxsxl_U5gcC6YQgd8ELIe4fT7AyrI",{"id":3666,"title":3667,"body":3668,"description":3857,"extension":251,"meta":3858,"navTitle":3667,"navigation":253,"order":3859,"path":143,"seo":3860,"stem":3861,"toc":3862,"__hash__":3869},"docs_en/docs/plugins.md","Plugins",{"type":8,"value":3669,"toc":3850},[3670,3683,3757,3805,3822],[11,3671,16,3674,16,3677,16,3680],{"id":3672,"className":3673},"what-plugins-are",[15],[18,3675,3676],{"id":3672},"What plugins are",[22,3678,3679],{},"\n    OpenPets plugins are small, optional JavaScript add-ons that run inside\n    the desktop app. They can schedule friendly reminders, react to local\n    time, or call approved HTTPS endpoints through the OpenPets SDK, then ask\n    your default pet to speak or react.\n  ",[22,3681,3682],{},"\n    Plugins are not AI-assistant integrations. They do not connect to your\n    editor, MCP client, shell, filesystem, or private project files. Install\n    only the plugins you want, and turn them off at any time from the desktop\n    tray.\n  ",[11,3684,16,3687,16,3691],{"id":3685,"className":3686},"official-plugins",[15],[18,3688,3690],{"id":3689},"official-first-party-plugins","Official first-party plugins",[65,3692,69,3694,16],{"className":3693},[68],[71,3695,73,3696,73,3705,69],{},[75,3697,77,3698,73],{},[79,3699,3700,3703],{},[82,3701,3702],{},"Plugin",[82,3704,1338],{},[89,3706,77,3707,77,3717,77,3727,77,3737,77,3747,73],{},[79,3708,3709,3714],{},[94,3710,3711],{},[32,3712,3713],{},"Ambient Companion",[94,3715,3716],{},"Adds calm time-of-day greetings and low-frequency companion messages.",[79,3718,3719,3724],{},[94,3720,3721],{},[32,3722,3723],{},"Break Buddy",[94,3725,3726],{},"Shows lightweight eye-rest, stretch, and hydration reminders.",[79,3728,3729,3734],{},[94,3730,3731],{},[32,3732,3733],{},"Pet Pal",[94,3735,3736],{},"Adds playful right-click actions such as cheer, celebrate, and calm down.",[79,3738,3739,3744],{},[94,3740,3741],{},[32,3742,3743],{},"Focus Buddy",[94,3745,3746],{},"Runs optional focus and break timers with pet reactions at each transition.",[79,3748,3749,3754],{},[94,3750,3751],{},[32,3752,3753],{},"GitHub Notifications",[94,3755,3756],{},"Checks configured public GitHub repositories for visible activity and lets your pet notify you.",[11,3758,16,3761,16,3764,16,3770],{"id":3759,"className":3760},"manage-plugins",[15],[18,3762,3763],{"id":3759},"Manage plugins",[22,3765,3766,3767,3769],{},"\n    Open the desktop tray menu and choose ",[32,3768,3667],{},". From there\n    you can browse the catalog, install official plugins, update installed\n    plugins, change settings, enable or disable a plugin, or uninstall it.\n  ",[1261,3771,69,3772,69,3775,69,3780,69,3785,69,3788,69,3793,69,3796,16],{},[226,3773,3774],{},"Open the OpenPets desktop tray menu.",[226,3776,3777,3778,231],{},"Select ",[32,3779,3667],{},[226,3781,3782,3783,231],{},"Choose a plugin from the catalog and click ",[32,3784,386],{},[226,3786,3787],{},"Review its permissions and approved network hosts.",[226,3789,1558,3790,3792],{},[32,3791,469],{}," for plugin-specific settings.",[226,3794,3795],{},"Use the enable toggle to start or stop the plugin without uninstalling it.",[226,3797,1558,3798,3801,3802,3804],{},[32,3799,3800],{},"Update"," when a newer version is available, or ",[32,3803,1514],{}," to remove it.",[11,3806,16,3809,16,3813,16,3816],{"id":3807,"className":3808},"permissions",[15],[18,3810,3812],{"id":3811},"permissions-and-network-access","Permissions and network access",[22,3814,3815],{},"\n    Every catalog plugin declares the capabilities it needs in its manifest.\n    OpenPets validates those permissions before the plugin is installed and\n    again before it runs. Network access is limited to approved HTTPS hosts;\n    plugins cannot open arbitrary URLs.\n  ",[22,3817,3818,3819,3821],{},"\n    The current ",[32,3820,3753],{}," plugin supports public\n    repositories only. It does not use OAuth, does not ask for a GitHub token,\n    and cannot read private repositories. Because it uses unauthenticated\n    GitHub API requests, GitHub may rate-limit checks if you configure many\n    repositories or refresh very often.\n  ",[11,3823,16,3825,16,3827],{"id":3548,"className":3824},[15],[18,3826,214],{"id":3548},[223,3828,69,3829,69,3836,69,3841,69,3844,69,3847,16],{},[226,3830,3831,3832,3835],{},"If a plugin stops working, open ",[32,3833,3834],{},"Tray → Plugins",", disable it, then enable it again.",[226,3837,1558,3838,3840],{},[32,3839,3800],{}," to make sure the installed ZIP matches the latest catalog version.",[226,3842,3843],{},"Check the plugin's configuration for missing required fields or unsupported repository names.",[226,3845,3846],{},"If OpenPets marks a plugin as broken, uninstall it and install it again from the catalog.",[226,3848,3849],{},"For reports, include the plugin name, version, what you expected, and the relevant desktop log lines. Do not include tokens, private repository names, or project paths.",{"title":244,"searchDepth":245,"depth":245,"links":3851},[3852,3853,3854,3855,3856],{"id":3672,"depth":245,"text":3676},{"id":3689,"depth":245,"text":3690},{"id":3759,"depth":245,"text":3763},{"id":3811,"depth":245,"text":3812},{"id":3548,"depth":245,"text":214},"Install, update, configure, enable, and troubleshoot OpenPets desktop plugins.",{},75,{"title":3667,"description":3857},"docs/plugins",[3863,3864,3866,3867,3868],{"id":3672,"label":3676},{"id":3685,"label":3865},"Official plugins",{"id":3759,"label":3763},{"id":3807,"label":3812},{"id":3548,"label":214},"LQEK4LoWtSGrlcWknl6DmD5PY4HMsihz6cbhUaVlFBA",{"id":3871,"title":3872,"body":3873,"description":5278,"extension":251,"meta":5279,"navTitle":3872,"navigation":253,"order":5280,"path":5281,"seo":5282,"stem":5283,"toc":5284,"__hash__":5297},"docs_en/docs/plugin-sdk.md","Plugin SDK",{"type":8,"value":3874,"toc":5247},[3875,3986,4070,4225,4460,4728,4845,4888,4919,5015,5066,5200],[11,3876,16,3878,16,3880,16,3883,16,3887,16,3890,16,3908,16,3922],{"id":1997,"className":3877},[15],[18,3879,2001],{"id":1997},[22,3881,3882],{},"\n    The OpenPets Plugin SDK lets you add small, optional behaviors to the\n    desktop pet — break nudges, focus timers, ambient greetings, playful\n    actions, or notifications from approved web endpoints. The desktop app\n    stays responsible for rendering pets, windows, persistence, permission\n    checks, and safety. A plugin is just a permissioned behavior layered on\n    top.\n  ",[3884,3885,3886],"blockquote",{},"\n    OpenPets is the pet runtime. Plugins are optional, permissioned behaviors\n    that make the pet feel useful and alive.\n  ",[22,3888,3889],{},"A plugin is two files:",[223,3891,69,3892,69,3898,16],{},[226,3893,3894,3897],{},[57,3895,3896],{},"openpets.plugin.json"," — a manifest declaring your id, version, entry file, requested permissions, and config schema.",[226,3899,3900,3901,3904,3905,231],{},"A single browser-compatible JavaScript ",[32,3902,3903],{},"entry file"," that calls ",[57,3906,3907],{},"OpenPetsPlugin.register({ start, stop })",[22,3909,3910,3911,3914,3915,3918,3919,378],{},"\n    Plugins talk to OpenPets only through a small, capability-based\n    ",[57,3912,3913],{},"ctx"," object passed to ",[57,3916,3917],{},"start(ctx)",". There is no Node,\n    no shell, no filesystem, and no arbitrary networking — see\n    ",[374,3920,3417],{"href":3921},"#how-it-works",[65,3923,69,3925,16],{"className":3924},[68],[71,3926,73,3927,73,3936,69],{},[75,3928,3929],{},[79,3930,3931,3934],{},[82,3932,3933],{},"Property",[82,3935,1908],{},[89,3937,77,3938,77,3949,77,3959,77,3970,77,3978,73],{},[79,3939,3940,3943],{},[94,3941,3942],{},"Manifest version",[94,3944,3945,3948],{},[57,3946,3947],{},"2"," (JavaScript plugins)",[79,3950,3951,3954],{},[94,3952,3953],{},"SDK version",[94,3955,3956],{},[57,3957,3958],{},"1.0.0",[79,3960,3961,3964],{},[94,3962,3963],{},"Runtime",[94,3965,3966,3969],{},[57,3967,3968],{},"javascript"," (sandboxed renderer)",[79,3971,3972,3975],{},[94,3973,3974],{},"Requires",[94,3976,3977],{},"OpenPets desktop 2.1.0+",[79,3979,3980,3983],{},[94,3981,3982],{},"Language",[94,3984,3985],{},"Browser-compatible JavaScript (no Node APIs)",[11,3987,16,3990,16,3992,16,3995,16,3999,16,4033,16,4037,16,4040,16,4063],{"id":3988,"className":3989},"how-it-works",[15],[18,3991,3417],{"id":3988},[22,3993,3994],{},"\n    Each enabled JavaScript plugin runs in its own hidden, locked-down Electron\n    renderer. The plugin never touches the main process directly. It only sees\n    the SDK object that is injected through a preload bridge, and every SDK call\n    crosses a validated IPC handler in the main process.\n  ",[826,3996,3998],{"id":3997},"the-sandbox","The sandbox",[223,4000,69,4001,69,4017,69,4020,69,4027,69,4030,16],{},[226,4002,4003,4004,4007,4008,859,4011,2038,4014,231],{},"Hidden ",[57,4005,4006],{},"BrowserWindow"," with ",[57,4009,4010],{},"nodeIntegration: false",[57,4012,4013],{},"contextIsolation: true",[57,4015,4016],{},"sandbox: true",[226,4018,4019],{},"A unique, non-persistent session partition per plugin run.",[226,4021,4022,4023,4026],{},"Raw renderer networking is blocked; downloads and ",[57,4024,4025],{},"window.open"," are denied; navigation/redirects after load are prevented.",[226,4028,4029],{},"Storage and cache are cleared when the plugin host stops.",[226,4031,4032],{},"Startup timeouts and crash/unresponsive handling mark a plugin broken instead of taking down the app.",[826,4034,4036],{"id":4035},"lifecycle","Lifecycle",[22,4038,4039],{},"When a plugin is enabled, OpenPets:",[1261,4041,69,4042,69,4045,69,4048,69,4051,69,4054,69,4057,16],{},[226,4043,4044],{},"Reads and validates the installed manifest.",[226,4046,4047],{},"Verifies the plugin is enabled and not catalog-disabled.",[226,4049,4050],{},"Verifies requested permissions and approved network hosts.",[226,4052,4053],{},"Resolves the JavaScript entry inside the install directory.",[226,4055,4056],{},"Creates an isolated host, injects the SDK preload, and runs the registration handshake.",[226,4058,4059,4060,4062],{},"Calls ",[57,4061,3917],{}," and keeps your schedules, commands, status, and config listeners alive.",[22,4064,4065,4066,4069],{},"\n    On reload, disable, uninstall, crash, or startup failure, OpenPets cancels\n    your schedules, clears commands/status/listeners, calls ",[57,4067,4068],{},"stop()","\n    when possible, and tears down the host window.\n  ",[11,4071,16,4074,16,4078,16,4084,16,4088,16,4103,16,4107,16,4139,16,4143,16,4153,16,4168,16,4188,16,4192,16,4200,16,4215],{"id":4072,"className":4073},"quickstart",[15],[18,4075,4077],{"id":4076},"your-first-plugin","Your first plugin",[22,4079,4080,4081,378],{},"\n    A plugin is a folder with a manifest and an entry file. Create a folder\n    anywhere on disk, for example ",[57,4082,4083],{},"~/openpets-plugins/hello-pet",[826,4085,4087],{"id":4086},"_1-the-manifest","1. The manifest",[65,4089,69,4091,69,4098,16],{"className":4090},[485],[65,4092,4094,4096],{"className":4093},[489],[491,4095,3896],{},[491,4097,3136],{},[498,4099,4100],{},[57,4101,4102],{},"{\n  \"manifestVersion\": 2,\n  \"id\": \"your-name.hello-pet\",\n  \"name\": \"Hello Pet\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Greets you when it starts and adds a hello command.\",\n  \"author\": \"Your Name\",\n  \"runtime\": \"javascript\",\n  \"entry\": \"index.js\",\n  \"sdkVersion\": \"1.0.0\",\n  \"permissions\": [\"pet:speak\", \"pet:reaction\", \"commands\", \"status\"],\n  \"configSchema\": {}\n}",[826,4104,4106],{"id":4105},"_2-the-entry-file","2. The entry file",[65,4108,69,4110,69,4119,16],{"className":4109},[485],[65,4111,4113,4116],{"className":4112},[489],[491,4114,4115],{},"index.js",[491,4117,4118],{},"js",[498,4120,4121,4134],{},[57,4122,4123,4124,4131],{},"OpenPetsPlugin.register({\n  async start(ctx) {\n    await ctx.status.set({ text: \"Ready to say hello\", tone: \"info\" })\n",[498,4125,4129],{"className":4126,"code":4128,"language":496},[4127],"language-text","await ctx.pet.speak(\"Hello! I am your new plugin.\")\nawait ctx.pet.react(\"waving\")\n\nawait ctx.commands.register(\n  { id: \"say-hello\", title: \"Say hello\", description: \"Get a friendly greeting.\" },\n  async () => {\n    await ctx.pet.speak(\"Hello again!\")\n    await ctx.pet.react(\"waving\")\n  },\n)\n",[57,4130,4128],{"__ignoreMap":244},[22,4132,4133],{},"},",[22,4135,4136],{},[57,4137,4138],{},"async stop() {\n// Optional cleanup. Schedules and commands are torn down for you.\n},\n})",[826,4140,4142],{"id":4141},"_3-editor-types-optional","3. Editor types (optional)",[22,4144,4145,4146,4149,4150,4152],{},"\n    There is no runtime SDK to import — the app injects ",[57,4147,4148],{},"OpenPetsPlugin","\n    and ",[57,4151,3913],{}," at load time. For autocomplete and type-checking,\n    install the types-only dev package and reference it from your entry file:\n  ",[65,4154,69,4156,69,4163,16],{"className":4155},[485],[65,4157,4159,4161],{"className":4158},[489],[491,4160,1303],{},[491,4162,1306],{},[498,4164,4165],{},[57,4166,4167],{},"npm i -D @open-pets/plugin-sdk",[65,4169,69,4171,69,4178,16],{"className":4170},[485],[65,4172,4174,4176],{"className":4173},[489],[491,4175,4115],{},[491,4177,4118],{},[498,4179,4180,4183],{},[57,4181,4182],{},"/// \u003Creference types=\"@open-pets/plugin-sdk\" />\n",[22,4184,4185],{},[57,4186,4187],{},"OpenPetsPlugin.register({ async start(ctx) { /* ctx is fully typed */ } })",[826,4189,4191],{"id":4190},"_4-load-it","4. Load it",[22,4193,4194,4195,4199],{},"\n    Point the desktop app at your folder and launch it with local plugin\n    support enabled (see ",[374,4196,4198],{"href":4197},"#local-dev","Local development","):\n  ",[65,4201,69,4203,69,4210,16],{"className":4202},[485],[65,4204,4206,4208],{"className":4205},[489],[491,4207,1303],{},[491,4209,1306],{},[498,4211,4212],{},[57,4213,4214],{},"OPENPETS_DEV_PLUGIN_PATHS=~/openpets-plugins/hello-pet pnpm dev:desktop:plugins",[22,4216,4217,4218,4220,4221,4224],{},"\n    Open ",[32,4219,3834],{},", confirm Hello Pet is enabled, then\n    right-click your pet to run the ",[32,4222,4223],{},"Say hello"," command.\n  ",[11,4226,16,4229,16,4233,16,4238,16,4442,16,4445],{"id":4227,"className":4228},"manifest",[15],[18,4230,4232],{"id":4231},"manifest-reference","Manifest reference",[22,4234,69,4235,4237],{},[57,4236,3896],{}," describes the plugin. OpenPets validates\n    it before install and again before each run.\n  ",[65,4239,69,4241,16],{"className":4240},[68],[71,4242,73,4243,73,4255,69],{},[75,4244,4245],{},[79,4246,4247,4250,4253],{},[82,4248,4249],{},"Field",[82,4251,4252],{},"Required",[82,4254,2502],{},[89,4256,77,4257,77,4273,77,4287,77,4299,77,4313,77,4324,77,4337,77,4356,77,4370,77,4384,77,4399,77,4414,77,4430,73],{},[79,4258,4259,4264,4267],{},[94,4260,4261],{},[57,4262,4263],{},"manifestVersion",[94,4265,4266],{},"Yes",[94,4268,4269,4270,4272],{},"Always ",[57,4271,3947],{}," for JavaScript plugins.",[79,4274,4275,4279,4281],{},[94,4276,4277],{},[57,4278,1651],{},[94,4280,4266],{},[94,4282,4283,4284,2438],{},"Stable package id. Reverse-DNS style (",[57,4285,4286],{},"your-name.my-plugin",[79,4288,4289,4294,4296],{},[94,4290,4291],{},[57,4292,4293],{},"name",[94,4295,4266],{},[94,4297,4298],{},"Human-readable display name.",[79,4300,4301,4306,4308],{},[94,4302,4303],{},[57,4304,4305],{},"version",[94,4307,4266],{},[94,4309,4310,4311,231],{},"Semver string, e.g. ",[57,4312,3958],{},[79,4314,4315,4319,4321],{},[94,4316,4317],{},[57,4318,1663],{},[94,4320,4266],{},[94,4322,4323],{},"Short summary shown in the Plugins UI.",[79,4325,4326,4331,4334],{},[94,4327,4328],{},[57,4329,4330],{},"author",[94,4332,4333],{},"No",[94,4335,4336],{},"Author or organization.",[79,4338,4339,4344,4346],{},[94,4340,4341],{},[57,4342,4343],{},"runtime",[94,4345,4266],{},[94,4347,4348,4351,4352,4355],{},[57,4349,4350],{},"\"javascript\""," (or ",[57,4353,4354],{},"\"declarative\""," for legacy v1).",[79,4357,4358,4363,4365],{},[94,4359,4360],{},[57,4361,4362],{},"entry",[94,4364,4266],{},[94,4366,4367,4368,231],{},"Relative path to the single JS entry, e.g. ",[57,4369,4115],{},[79,4371,4372,4377,4379],{},[94,4373,4374],{},[57,4375,4376],{},"sdkVersion",[94,4378,4266],{},[94,4380,4381,4382,231],{},"SDK contract expected by the plugin, e.g. ",[57,4383,3958],{},[79,4385,4386,4390,4392],{},[94,4387,4388],{},[57,4389,3807],{},[94,4391,4266],{},[94,4393,4394,4395,231],{},"Array of declared capabilities — see ",[374,4396,4398],{"href":4397},"#permissions","Permissions",[79,4400,4401,4406,4408],{},[94,4402,4403],{},[57,4404,4405],{},"network.hosts",[94,4407,4333],{},[94,4409,4410,4411,231],{},"Exact HTTPS hostnames the plugin may request. Required if you use ",[57,4412,4413],{},"http",[79,4415,4416,4421,4423],{},[94,4417,4418],{},[57,4419,4420],{},"configSchema",[94,4422,4333],{},[94,4424,4425,4426,231],{},"Host-rendered settings schema — see ",[374,4427,4429],{"href":4428},"#config-schema","Config schema",[79,4431,4432,4437,4439],{},[94,4433,4434],{},[57,4435,4436],{},"icon",[94,4438,4333],{},[94,4440,4441],{},"Optional icon hint for the Plugins UI.",[22,4443,4444],{},"If a plugin makes network requests, declare the hosts:",[65,4446,69,4448,69,4455,16],{"className":4447},[485],[65,4449,4451,4453],{"className":4450},[489],[491,4452,3896],{},[491,4454,3136],{},[498,4456,4457],{},[57,4458,4459],{},"{\n  \"permissions\": [\"network\", \"schedule\", \"storage\", \"status\", \"pet:speak\"],\n  \"network\": { \"hosts\": [\"api.github.com\"] }\n}",[11,4461,16,4464,16,4468,16,4474,16,4478,16,4491,16,4507,16,4519,16,4523,16,4529,16,4544,16,4555,16,4559,16,4565,16,4580,16,4583,16,4587,16,4592,16,4607,16,4611,16,4617,16,4632,16,4643,16,4647,16,4652,16,4667,16,4671,16,4680,16,4695,16,4702,16,4706,16,4713],{"id":4462,"className":4463},"sdk-reference",[15],[18,4465,4467],{"id":4466},"sdk-ctx-reference","SDK (ctx) reference",[22,4469,4470,4471,4473],{},"\n    Your ",[57,4472,3917],{}," handler receives the capability object below.\n    Every method is async and returns a Promise. Methods are only present when\n    the matching permission is granted.\n  ",[826,4475,4477],{"id":4476},"ctxpet","ctx.pet",[22,4479,4480,4481,859,4484,4487,4488,231],{},"Make the default pet speak, react, or move. Requires ",[57,4482,4483],{},"pet:speak",[57,4485,4486],{},"pet:reaction",", or ",[57,4489,4490],{},"pet:move",[65,4492,69,4494,69,4502,16],{"className":4493},[485],[65,4495,4497,4499],{"className":4496},[489],[491,4498,4477],{},[491,4500,4501],{},"ts",[498,4503,4504],{},[57,4505,4506],{},"pet.speak(message: string): Promise\u003Cvoid>\npet.react(reaction: string): Promise\u003Cvoid>\npet.moveBy(options: { x: number; y: number; durationMs?: number }): Promise\u003Cvoid>\npet.wander(options: { distance?: number; durationMs?: number }): Promise\u003Cvoid>\npet.moveToHome(): Promise\u003Cvoid>",[22,4508,4509,4510,859,4512,863,4514,2038,4516,4518],{},"\n    Common reactions are ",[57,4511,1150],{},[57,4513,1140],{},[57,4515,1160],{},[57,4517,1180],{},". Messages are capped at\n    140 characters and rejected if they look like code, URLs, paths, or\n    secrets. Movement only affects the default pet, is clamped to the work\n    area, and is skipped while the pet is hidden, paused, dragging, or busy.\n  ",[826,4520,4522],{"id":4521},"ctxschedule","ctx.schedule",[22,4524,4525,4526,231],{},"Run callbacks later, on an interval, or daily. Requires ",[57,4527,4528],{},"schedule",[65,4530,69,4532,69,4539,16],{"className":4531},[485],[65,4533,4535,4537],{"className":4534},[489],[491,4536,4522],{},[491,4538,4501],{},[498,4540,4541],{},[57,4542,4543],{},"schedule.once(id: string, delayMs: number, handler: () => void | Promise\u003Cvoid>): Promise\u003Cvoid>\nschedule.every(id: string, intervalMs: number, handler: () => void | Promise\u003Cvoid>): Promise\u003Cvoid>\nschedule.daily(id: string, spec: string | { time: string; days?: number[] }, handler): Promise\u003Cvoid>\nschedule.cancel(id: string): Promise\u003Cvoid>\nschedule.cancelAll(): Promise\u003Cvoid>",[22,4545,4546,4547,4550,4551,4554],{},"\n    Schedule ids must be short, safe identifiers. Intervals have a minimum\n    delay. Daily schedules use ",[57,4548,4549],{},"HH:mm"," and optional weekdays\n    ",[57,4552,4553],{},"0–6"," (Sunday = 0).\n  ",[826,4556,4558],{"id":4557},"ctxstorage","ctx.storage",[22,4560,4561,4562,231],{},"Persist small per-plugin state across restarts. Requires ",[57,4563,4564],{},"storage",[65,4566,69,4568,69,4575,16],{"className":4567},[485],[65,4569,4571,4573],{"className":4570},[489],[491,4572,4558],{},[491,4574,4501],{},[498,4576,4577],{},[57,4578,4579],{},"storage.get\u003CT>(key: string): Promise\u003CT | undefined>\nstorage.set(key: string, value: unknown): Promise\u003Cvoid>\nstorage.delete(key: string): Promise\u003Cvoid>",[22,4581,4582],{},"\n    Storage is stored outside config in a per-plugin file. Keys are\n    restricted and there is a size quota. Values must be clone-safe (no\n    functions, DOM nodes, etc.). Uninstalling removes the storage file.\n  ",[826,4584,4586],{"id":4585},"ctxconfig","ctx.config",[22,4588,4589,4590,231],{},"Read user configuration and react to changes. Always available; the shape comes from your ",[57,4591,4420],{},[65,4593,69,4595,69,4602,16],{"className":4594},[485],[65,4596,4598,4600],{"className":4597},[489],[491,4599,4586],{},[491,4601,4501],{},[498,4603,4604],{},[57,4605,4606],{},"config.get\u003CT>(): Promise\u003CT>\nconfig.onChange(handler: (config: T) => void | Promise\u003Cvoid>): () => void  // returns an unsubscribe fn",[826,4608,4610],{"id":4609},"ctxcommands","ctx.commands",[22,4612,4613,4614,231],{},"Register right-click pet actions, optionally with a small input form. Requires ",[57,4615,4616],{},"commands",[65,4618,69,4620,69,4627,16],{"className":4619},[485],[65,4621,4623,4625],{"className":4622},[489],[491,4624,4610],{},[491,4626,4501],{},[498,4628,4629],{},[57,4630,4631],{},"commands.register(\n  command: {\n    id: string\n    title: string\n    description?: string\n    form?: {\n      submitLabel?: string\n      fields: Array\u003C{\n        id: string\n        type: \"text\" | \"textarea\" | \"number\"\n        label: string\n        default?: string | number\n        min?: number\n        max?: number\n        maxLength?: number\n        required?: boolean\n      }>\n    }\n  },\n  handler: (values?: Record\u003Cstring, unknown>) => void | Promise\u003Cvoid>,\n): Promise\u003Cvoid>\ncommands.unregister(id: string): Promise\u003Cvoid>",[22,4633,4634,4635,4638,4639,4642],{},"\n    When a command declares a ",[57,4636,4637],{},"form",", the pet context menu opens a\n    host-rendered dialog and passes validated ",[57,4640,4641],{},"values"," to your\n    handler.\n  ",[826,4644,4646],{"id":4645},"ctxstatus","ctx.status",[22,4648,4649,4650,231],{},"Show a short status line in the Plugins UI. Requires ",[57,4651,862],{},[65,4653,69,4655,69,4662,16],{"className":4654},[485],[65,4656,4658,4660],{"className":4657},[489],[491,4659,4646],{},[491,4661,4501],{},[498,4663,4664],{},[57,4665,4666],{},"status.set(status: string | { text: string; tone?: \"info\" | \"success\" | \"warning\" | \"error\" }): Promise\u003Cvoid>\nstatus.clear(): Promise\u003Cvoid>",[826,4668,4670],{"id":4669},"ctxhttp","ctx.http",[22,4672,4673,4674,4677,4678,231],{},"Fetch approved HTTPS endpoints through the OpenPets proxy. Requires ",[57,4675,4676],{},"network"," and matching ",[57,4679,4405],{},[65,4681,69,4683,69,4690,16],{"className":4682},[485],[65,4684,4686,4688],{"className":4685},[489],[491,4687,4670],{},[491,4689,4501],{},[498,4691,4692],{},[57,4693,4694],{},"http.fetch(url: string, options?: {\n  method?: \"GET\"\n  headers?: Record\u003Cstring, string>\n  timeoutMs?: number\n}): Promise\u003C{\n  status: number\n  ok: boolean\n  headers: Record\u003Cstring, string>\n  text: string\n  json?: unknown\n}>",[22,4696,4697,4698,4701],{},"\n    HTTP is ",[32,4699,4700],{},"GET-only, HTTPS-only",", redirect-blocked,\n    response-size capped, and host-allowlisted. Hostnames are DNS-checked to\n    block private/loopback/metadata targets.\n  ",[826,4703,4705],{"id":4704},"ctxlog","ctx.log",[22,4707,4708,4709,4712],{},"Write to the desktop app log under the ",[57,4710,4711],{},"plugin"," scope. Always available.",[65,4714,69,4716,69,4723,16],{"className":4715},[485],[65,4717,4719,4721],{"className":4718},[489],[491,4720,4705],{},[491,4722,4501],{},[498,4724,4725],{},[57,4726,4727],{},"log.debug(...args: unknown[]): Promise\u003Cvoid>\nlog.info(...args: unknown[]): Promise\u003Cvoid>\nlog.warn(...args: unknown[]): Promise\u003Cvoid>\nlog.error(...args: unknown[]): Promise\u003Cvoid>",[11,4729,16,4731,16,4733,16,4739],{"id":3807,"className":4730},[15],[18,4732,4398],{"id":3807},[22,4734,4735,4736,4738],{},"\n    Plugins must declare every capability they use in the manifest's\n    ",[57,4737,3807],{}," array. Changing permissions — or adding network\n    hosts — requires the user to re-approve the plugin.\n  ",[65,4740,69,4742,16],{"className":4741},[68],[71,4743,73,4744,73,4754,69],{},[75,4745,4746],{},[79,4747,4748,4751],{},[82,4749,4750],{},"Permission",[82,4752,4753],{},"Grants",[89,4755,77,4756,77,4768,77,4780,77,4798,77,4807,77,4816,77,4825,77,4834,73],{},[79,4757,4758,4762],{},[94,4759,4760],{},[57,4761,4483],{},[94,4763,4764,4765,231],{},"Show pet speech bubbles via ",[57,4766,4767],{},"ctx.pet.speak",[79,4769,4770,4774],{},[94,4771,4772],{},[57,4773,4486],{},[94,4775,4776,4777,231],{},"Trigger pet reactions via ",[57,4778,4779],{},"ctx.pet.react",[79,4781,4782,4786],{},[94,4783,4784],{},[57,4785,4490],{},[94,4787,4788,4789,859,4792,859,4795,2438],{},"Bounded default-pet movement (",[57,4790,4791],{},"moveBy",[57,4793,4794],{},"wander",[57,4796,4797],{},"moveToHome",[79,4799,4800,4804],{},[94,4801,4802],{},[57,4803,4528],{},[94,4805,4806],{},"One-shot, interval, and daily callbacks.",[79,4808,4809,4813],{},[94,4810,4811],{},[57,4812,4564],{},[94,4814,4815],{},"Per-plugin persisted state.",[79,4817,4818,4822],{},[94,4819,4820],{},[57,4821,862],{},[94,4823,4824],{},"Status text/tone in the Plugins UI.",[79,4826,4827,4831],{},[94,4828,4829],{},[57,4830,4616],{},[94,4832,4833],{},"Host-rendered commands and command forms.",[79,4835,4836,4840],{},[94,4837,4838],{},[57,4839,4676],{},[94,4841,4842,4843,231],{},"HTTPS GET requests to approved hosts via ",[57,4844,4670],{},[11,4846,16,4849,16,4853,16,4856,16,4882],{"id":4847,"className":4848},"limits",[15],[18,4850,4852],{"id":4851},"validation-limits","Validation & limits",[22,4854,4855],{},"\n    The main-process SDK bridge validates and rate-limits everything a plugin\n    does. Design around these guarantees rather than fighting them:\n  ",[223,4857,69,4858,69,4861,69,4864,69,4867,69,4870,69,4873,69,4876,69,4879,16],{},[226,4859,4860],{},"Pet messages are length-capped (140 chars) and rejected if they resemble code, URLs, file paths, or secrets.",[226,4862,4863],{},"Pet movement is clamped to the work area, capped per move, and skipped while hidden/paused/dragging/busy.",[226,4865,4866],{},"Schedule, command, and storage ids must be short, safe identifiers; intervals have a minimum delay.",[226,4868,4869],{},"Storage has a per-plugin size quota and restricted keys.",[226,4871,4872],{},"Status text and command title/description have length limits.",[226,4874,4875],{},"HTTP is GET-only, HTTPS-only, redirect-blocked, response-size capped, and DNS-checked against private targets.",[226,4877,4878],{},"Pet actions, logs, and HTTP calls each have per-minute rate limits.",[226,4880,4881],{},"All values crossing the SDK IPC boundary must be clone-safe.",[22,4883,4884,4885,4887],{},"The platform intentionally does ",[32,4886,465],{}," provide Node APIs, main-process execution, shell, native modules, package installs, broad filesystem access, wildcard networking, or plugin-rendered settings UI.",[11,4889,16,4892,16,4894,16,4904],{"id":4890,"className":4891},"config-schema",[15],[18,4893,4429],{"id":4890},[22,4895,4896,4897,4899,4900,4903],{},"\n    OpenPets renders plugin settings itself — plugins never draw their own UI.\n    Declare fields in ",[57,4898,4420],{}," and read the resulting values\n    through ",[57,4901,4902],{},"ctx.config.get()",". Supported field types include text,\n    textarea, number, boolean, select, time, list, and multi-select.\n  ",[65,4905,69,4907,69,4914,16],{"className":4906},[485],[65,4908,4910,4912],{"className":4909},[489],[491,4911,4420],{},[491,4913,3136],{},[498,4915,4916],{},[57,4917,4918],{},"\"configSchema\": {\n  \"quietHoursEnabled\": { \"type\": \"boolean\", \"label\": \"Quiet hours\", \"default\": true },\n  \"quietStart\": { \"type\": \"time\", \"label\": \"Quiet start\", \"default\": \"22:00\" },\n  \"snoozeMinutes\": { \"type\": \"number\", \"label\": \"Snooze minutes\", \"default\": 15, \"min\": 1, \"max\": 120, \"step\": 5 },\n  \"breaks\": {\n    \"type\": \"list\",\n    \"label\": \"Break reminders\",\n    \"maxItems\": 8,\n    \"itemSchema\": {\n      \"message\": { \"type\": \"textarea\", \"label\": \"Message\", \"maxLength\": 140 },\n      \"reaction\": {\n        \"type\": \"select\",\n        \"label\": \"Reaction\",\n        \"default\": \"waiting\",\n        \"options\": [\n          { \"label\": \"Waving\", \"value\": \"waving\" },\n          { \"label\": \"Waiting\", \"value\": \"waiting\" },\n          { \"label\": \"Success\", \"value\": \"success\" }\n        ]\n      },\n      \"intervalMinutes\": { \"type\": \"number\", \"label\": \"Interval minutes\", \"default\": 60, \"min\": 10, \"max\": 1440 }\n    }\n  }\n}",[11,4920,16,4923,16,4926,16,4933,16,4970,16,4973,16,4988,16,4991,16,5006],{"id":4921,"className":4922},"local-dev",[15],[18,4924,4198],{"id":4925},"local-development",[22,4927,4928,4929,4932],{},"\n    Local plugin loading is explicit and development-only. The desktop app\n    reads path lists from environment variables and snapshots each plugin into\n    its app-data ",[57,4930,4931],{},"plugins-dev"," directory, auto-approving permissions\n    for those explicit dev paths.\n  ",[65,4934,69,4936,16],{"className":4935},[68],[71,4937,73,4938,73,4946,69],{},[75,4939,4940],{},[79,4941,4942,4944],{},[82,4943,2864],{},[82,4945,2818],{},[89,4947,77,4948,77,4960,73],{},[79,4949,4950,4955],{},[94,4951,4952],{},[57,4953,4954],{},"OPENPETS_DEV_PLUGIN_ROOTS",[94,4956,4957,4958,231],{},"Directories whose child folders are scanned for ",[57,4959,3896],{},[79,4961,4962,4967],{},[94,4963,4964],{},[57,4965,4966],{},"OPENPETS_DEV_PLUGIN_PATHS",[94,4968,4969],{},"Exact plugin folders to load.",[22,4971,4972],{},"From the repo root, load the official plugins for dogfooding:",[65,4974,69,4976,69,4983,16],{"className":4975},[485],[65,4977,4979,4981],{"className":4978},[489],[491,4980,1303],{},[491,4982,1306],{},[498,4984,4985],{},[57,4986,4987],{},"pnpm dev:desktop:plugins",[22,4989,4990],{},"Or load one plugin by path:",[65,4992,69,4994,69,5001,16],{"className":4993},[485],[65,4995,4997,4999],{"className":4996},[489],[491,4998,1303],{},[491,5000,1306],{},[498,5002,5003],{},[57,5004,5005],{},"OPENPETS_DEV_PLUGIN_PATHS=/absolute/path/to/plugin pnpm dev:desktop",[22,5007,5008,5009,5011,5012,378],{},"\n    After editing plugin source, reload or re-load the plugin from the Plugins\n    UI so the snapshot updates. Plugin runtime events use the\n    ",[57,5010,4711],{}," log scope in ",[57,5013,5014],{},"openpets.log",[11,5016,16,5019,16,5023,16,5030,16,5045,16,5048,16,5063],{"id":5017,"className":5018},"publishing",[15],[18,5020,5022],{"id":5021},"packaging-publishing","Packaging & publishing",[22,5024,5025,5026,5029],{},"\n    Plugins are distributed through the catalog at\n    ",[57,5027,5028],{},"https://openpets.dev/plugins/catalog.v2.json",". From the repo\n    root, validate and stage a package locally without uploading:\n  ",[65,5031,69,5033,69,5040,16],{"className":5032},[485],[65,5034,5036,5038],{"className":5035},[489],[491,5037,1303],{},[491,5039,1306],{},[498,5041,5042],{},[57,5043,5044],{},"pnpm plugins:test     # run plugin contract checks\npnpm plugins:check    # dry-run package validation\npnpm plugins:package  # write web/public/plugins/*.json and stage ZIPs locally",[22,5046,5047],{},"Publishing the staged artifacts is a separate, explicit step:",[65,5049,69,5051,69,5058,16],{"className":5050},[485],[65,5052,5054,5056],{"className":5053},[489],[491,5055,1303],{},[491,5057,1306],{},[498,5059,5060],{},[57,5061,5062],{},"pnpm plugins:publish\npnpm plugins:deploy",[22,5064,5065],{},"\n    Plugin ZIP installs are validated end-to-end: catalog id/version match,\n    SHA-256 package hash, ZIP path safety, manifest presence and id/version\n    match, JavaScript entry presence, and safe install/uninstall containment.\n  ",[11,5067,16,5070,16,5073,16,5080,16,5171,16,5174],{"id":5068,"className":5069},"examples",[15],[18,5071,5072],{"id":5068},"Examples",[22,5074,5075,5076,5079],{},"\n    The seven first-party plugins are the best reference for real, reviewed SDK\n    usage. Read their source under ",[57,5077,5078],{},"plugins/official/"," in the\n    repository:\n  ",[65,5081,69,5083,16],{"className":5082},[68],[71,5084,73,5085,73,5094,69],{},[75,5086,5087],{},[79,5088,5089,5091],{},[82,5090,3702],{},[82,5092,5093],{},"Shows how to use",[89,5095,77,5096,77,5105,77,5118,77,5127,77,5137,77,5146,77,5159,73],{},[79,5097,5098,5102],{},[94,5099,5100],{},[32,5101,3733],{},[94,5103,5104],{},"Commands + pet speech/reactions — the simplest example.",[79,5106,5107,5111],{},[94,5108,5109],{},[32,5110,3723],{},[94,5112,5113,5114,5117],{},"Interval schedules, config + ",[57,5115,5116],{},"onChange",", storage, status, quiet hours.",[79,5119,5120,5124],{},[94,5121,5122],{},[32,5123,3743],{},[94,5125,5126],{},"State machine over storage, phase timers, start/pause/stop commands.",[79,5128,5129,5134],{},[94,5130,5131],{},[32,5132,5133],{},"Quick Reminders",[94,5135,5136],{},"Command forms, one-shot schedules, status.",[79,5138,5139,5143],{},[94,5140,5141],{},[32,5142,3713],{},[94,5144,5145],{},"Daily schedules, time-of-day logic, low-frequency reactions.",[79,5147,5148,5153],{},[94,5149,5150],{},[32,5151,5152],{},"Wander Buddy",[94,5154,5155,5156,5158],{},"Bounded ",[57,5157,4490],{}," movement on a schedule.",[79,5160,5161,5165],{},[94,5162,5163],{},[32,5164,3753],{},[94,5166,5167,5168,5170],{},"Approved ",[57,5169,4676],{}," HTTP, etags/baselines in storage, polling.",[22,5172,5173],{},"A complete interval-reminder pattern, distilled from Break Buddy:",[65,5175,69,5177,69,5184,16],{"className":5176},[485],[65,5178,5180,5182],{"className":5179},[489],[491,5181,4115],{},[491,5183,4118],{},[498,5185,5186,5195],{},[57,5187,5188,5189],{},"OpenPetsPlugin.register({\n  async start(ctx) {\n    async function schedule(config) {\n      await ctx.schedule.cancelAll()\n      const minutes = Number(config.intervalMinutes) || 60\n      await ctx.schedule.every(\"reminder\", minutes * 60_000, async () => {\n        await ctx.pet.speak(\"Time to stretch.\")\n        await ctx.pet.react(\"waving\")\n        await ctx.storage.set(\"lastFired\", new Date().toISOString())\n      })\n      await ctx.status.set({ text: `Reminder every ${minutes} min`, tone: \"info\" })\n    }\n",[498,5190,5193],{"className":5191,"code":5192,"language":496},[4127],"await schedule(await ctx.config.get())\nctx.config.onChange(async (next) => schedule(next))\n",[57,5194,5192],{"__ignoreMap":244},[22,5196,5197],{},[57,5198,5199],{},"},\nasync stop() {},\n})",[11,5201,16,5204,16,5208],{"id":5202,"className":5203},"next",[15],[18,5205,5207],{"id":5206},"where-to-go-next","Where to go next",[223,5209,69,5210,69,5217,69,5224,69,5230,69,5237,16],{},[226,5211,5212,5216],{},[41,5213,5215],{"to":5214},"/sdk","SDK overview"," — the developer landing page with capabilities and quickstart.",[226,5218,5219,5223],{},[41,5220,5222],{"to":5221},"/plugins","Plugin catalog"," — browse the official plugins users can install.",[226,5225,5226,5229],{},[41,5227,5228],{"to":143},"Using plugins"," — install, configure, and manage plugins as an end user.",[226,5231,5232,5236],{},[41,5233,5235],{"to":5234},"/docs/developer","Developer guide"," — building, testing, and releasing OpenPets itself.",[226,5238,5239,5246],{},[374,5240,5245],{"href":5241,"target":5242,"rel":5243},"https://github.com/alvinunreal/openpets/tree/main/plugins/official","_blank",[5244],"noopener","Official plugin source on GitHub"," — seven reviewed, real-world examples.",{"title":244,"searchDepth":245,"depth":245,"links":5248},[5249,5250,5254,5260,5261,5271,5272,5273,5274,5275,5276,5277],{"id":1997,"depth":245,"text":2001},{"id":3988,"depth":245,"text":3417,"children":5251},[5252,5253],{"id":3997,"depth":1196,"text":3998},{"id":4035,"depth":1196,"text":4036},{"id":4076,"depth":245,"text":4077,"children":5255},[5256,5257,5258,5259],{"id":4086,"depth":1196,"text":4087},{"id":4105,"depth":1196,"text":4106},{"id":4141,"depth":1196,"text":4142},{"id":4190,"depth":1196,"text":4191},{"id":4231,"depth":245,"text":4232},{"id":4466,"depth":245,"text":4467,"children":5262},[5263,5264,5265,5266,5267,5268,5269,5270],{"id":4476,"depth":1196,"text":4477},{"id":4521,"depth":1196,"text":4522},{"id":4557,"depth":1196,"text":4558},{"id":4585,"depth":1196,"text":4586},{"id":4609,"depth":1196,"text":4610},{"id":4645,"depth":1196,"text":4646},{"id":4669,"depth":1196,"text":4670},{"id":4704,"depth":1196,"text":4705},{"id":3807,"depth":245,"text":4398},{"id":4851,"depth":245,"text":4852},{"id":4890,"depth":245,"text":4429},{"id":4925,"depth":245,"text":4198},{"id":5021,"depth":245,"text":5022},{"id":5068,"depth":245,"text":5072},{"id":5206,"depth":245,"text":5207},"Build OpenPets plugins with the JavaScript SDK: runtime model, manifest, the full ctx API, permissions, limits, local development, and publishing.",{},76,"/docs/plugin-sdk",{"title":3872,"description":5278},"docs/plugin-sdk",[5285,5286,5287,5288,5289,5290,5291,5292,5293,5294,5295,5296],{"id":1997,"label":2001},{"id":3988,"label":3417},{"id":4072,"label":4077},{"id":4227,"label":4232},{"id":4462,"label":4467},{"id":3807,"label":4398},{"id":4847,"label":4852},{"id":4890,"label":4429},{"id":4921,"label":4198},{"id":5017,"label":5022},{"id":5068,"label":5072},{"id":5202,"label":5207},"EhyNtWhURCv-abJfPZica7cVpTYw7hBATVUPePo8Z78",{"id":5299,"title":176,"body":5300,"description":5646,"extension":251,"meta":5647,"navTitle":5648,"navigation":253,"order":5649,"path":175,"seo":5650,"stem":5651,"toc":5652,"__hash__":5659},"docs_en/docs/pet-format.md",{"type":8,"value":5301,"toc":5634},[5302,5339,5437,5462,5535,5619],[11,5303,16,5306,16,5310,16,5315,16,5330],{"id":5304,"className":5305},"layout",[15],[18,5307,5309],{"id":5308},"package-layout","Package layout",[22,5311,5312,5313,378],{},"\n    A pet is a small folder containing a metadata file and a spritesheet.\n    For the gallery, the folder is zipped up and hosted on\n    ",[57,5314,1710],{},[65,5316,69,5318,69,5325,16],{"className":5317},[485],[65,5319,5321,5323],{"className":5320},[489],[491,5322,1825],{},[491,5324,496],{},[498,5326,5327],{},[57,5328,5329],{},"\u003Cpet-id>/\n├── pet.json\n├── spritesheet.webp\n└── preview.webp    # optional, used as a thumbnail",[22,5331,5332,5333,5335,5336,5338],{},"\n    The folder name must equal the ",[57,5334,1651],{}," inside ",[57,5337,1841],{},".\n    There is no special \"root\" inside the ZIP — the entries live directly at\n    the top level of the archive.\n  ",[11,5340,16,5343,16,5348,16,5351,16,5366],{"id":5341,"className":5342},"pet-json",[15],[18,5344,5346],{"id":5345},"petjson",[57,5347,1841],{},[22,5349,5350],{},"\n    Metadata describing the pet. All fields are required unless marked\n    optional.\n  ",[65,5352,69,5354,69,5361,16],{"className":5353},[485],[65,5355,5357,5359],{"className":5356},[489],[491,5358,1841],{},[491,5360,3136],{},[498,5362,5363],{},[57,5364,5365],{},"{\n  \"id\": \"my-pet\",\n  \"displayName\": \"My Pet\",\n  \"description\": \"A friendly companion that loves test suites.\",\n  \"spritesheetPath\": \"spritesheet.webp\"\n}",[65,5367,69,5369,16],{"className":5368},[68],[71,5370,73,5371,73,5383,69],{},[75,5372,77,5373,73],{},[79,5374,5375,5377,5380],{},[82,5376,4249],{},[82,5378,5379],{},"Type",[82,5381,5382],{},"Constraints",[89,5384,77,5385,77,5400,77,5411,77,5422,73],{},[79,5386,300,5387,300,5391,300,5394,77],{},[94,5388,5389],{},[57,5390,1651],{},[94,5392,5393],{},"string",[94,5395,5396,5397,5399],{},"Lowercase letters, digits, hyphens, underscores. Must start with a letter or digit. 1–64 characters. Cannot be ",[57,5398,1964],{},". Must match the folder name.",[79,5401,300,5402,300,5406,300,5408,77],{},[94,5403,5404],{},[57,5405,1657],{},[94,5407,5393],{},[94,5409,5410],{},"Non-empty after trimming. Maximum 80 characters.",[79,5412,300,5413,300,5417,300,5419,77],{},[94,5414,5415],{},[57,5416,1663],{},[94,5418,5393],{},[94,5420,5421],{},"Non-empty after trimming. Maximum 500 characters.",[79,5423,300,5424,300,5429,300,5431,77],{},[94,5425,5426],{},[57,5427,5428],{},"spritesheetPath",[94,5430,5393],{},[94,5432,5433,5434,231],{},"Must be the literal string ",[57,5435,5436],{},"\"spritesheet.webp\"",[11,5438,16,5441,16,5444,16,5450,16,5459],{"id":5439,"className":5440},"spritesheet",[15],[18,5442,5443],{"id":5439},"Spritesheet",[22,5445,5446,5447,5449],{},"\n    The spritesheet is a single WebP image at the file named in\n    ",[57,5448,5428],{},". It contains the animation frames for every\n    reaction your pet supports.\n  ",[22,5451,5452,5453,884,5455,5458],{},"\n    A pet does not have to implement every reaction. Reactions that have no\n    frames in the spritesheet fall back to ",[57,5454,1080],{},[41,5456,5457],{"to":3313},"reactions list"," for the\n    full set.\n  ",[22,5460,5461],{},"\n    Look at the source of any existing gallery pet (or the built-in pet that\n    ships with OpenPets) for an example sprite layout. There is no required\n    cell size — the desktop renderer reads frame coordinates from the pet's\n    spritesheet metadata.\n  ",[11,5463,16,5466,16,5470,16,5473,16,5477,16,5494,16,5498,16,5522,16,5526],{"id":5464,"className":5465},"validation",[15],[18,5467,5469],{"id":5468},"validation-rules","Validation rules",[22,5471,5472],{},"\n    OpenPets validates every pet before it is written to disk. Some checks\n    apply to the ZIP file as a whole; some apply to each entry inside.\n  ",[826,5474,5476],{"id":5475},"zip-level-limits","ZIP-level limits",[223,5478,69,5479,69,5482,69,5485,69,5488,69,5491,16],{},[226,5480,5481],{},"Downloaded ZIP must be no larger than 50 MB.",[226,5483,5484],{},"Extracted total size must be no larger than 200 MB.",[226,5486,5487],{},"No more than 500 entries.",[226,5489,5490],{},"Individual file size must be no larger than 100 MB.",[226,5492,5493],{},"The ZIP magic bytes are verified before extraction begins.",[826,5495,5497],{"id":5496},"per-entry-rules","Per-entry rules",[223,5499,69,5500,69,5507,69,5510,69,5519,16],{},[226,5501,5502,5503,5506],{},"Paths must stay inside the pet directory — no ",[57,5504,5505],{},".."," traversal.",[226,5508,5509],{},"No symlinks, no encrypted entries, no unsupported compression methods.",[226,5511,5512,5513,35,5516,2438],{},"Case collisions are rejected (so a pet cannot contain both ",[57,5514,5515],{},"image.png",[57,5517,5518],{},"Image.png",[226,5520,5521],{},"Entry Unix mode must be a valid file or directory mode.",[826,5523,5525],{"id":5524},"required-files-after-extraction","Required files after extraction",[22,5527,5528,5529,5531,5532,5534],{},"\n    A pet must contain ",[57,5530,1841],{}," and the file named by\n    ",[57,5533,5428],{},". If either is missing, the install is\n    rejected and nothing is written to your installed-pets directory.\n  ",[11,5536,16,5539,16,5543,16,5549,16,5552,16,5608],{"id":5537,"className":5538},"codex-pets",[15],[18,5540,5542],{"id":5541},"codex-local-dev-pets","Codex (local-dev) pets",[22,5544,5545,5546,5548],{},"\n    During development you do not need to package a pet as a ZIP. Drop the\n    folder into ",[57,5547,1815],{}," and the desktop app imports it\n    live.\n  ",[22,5550,5551],{},"\n    Codex pets have slightly different limits because they are unzipped on\n    disk:\n  ",[65,5553,69,5555,16],{"className":5554},[68],[71,5556,73,5557,73,5565,69],{},[75,5558,77,5559,73],{},[79,5560,5561,5563],{},[82,5562,1905],{},[82,5564,1908],{},[89,5566,77,5567,77,5575,77,5585,77,5592,77,5600,73],{},[79,5568,5569,5572],{},[94,5570,5571],{},"Maximum codex pets imported",[94,5573,5574],{},"100",[79,5576,5577,5582],{},[94,5578,5579,5581],{},[57,5580,1841],{}," file size",[94,5583,5584],{},"128 KB",[79,5586,5587,5590],{},[94,5588,5589],{},"Spritesheet size",[94,5591,1950],{},[79,5593,5594,5597],{},[94,5595,5596],{},"Preview image size",[94,5598,5599],{},"8 MB",[79,5601,5602,5605],{},[94,5603,5604],{},"Total preview bytes across all pets",[94,5606,5607],{},"24 MB",[22,5609,5610,5611,5613,5614,5335,5616,5618],{},"\n    The folder name in ",[57,5612,1815],{}," must match the\n    ",[57,5615,1651],{},[57,5617,1841],{},". Reload OpenPets after\n    changing files in a codex pet folder.\n  ",[11,5620,16,5622,16,5626],{"id":5017,"className":5621},[15],[18,5623,5625],{"id":5624},"publishing-a-pet","Publishing a pet",[22,5627,5628,5629,5633],{},"\n    Once your pet is ready, submit it to the OpenPets gallery. There is a\n    pet-submission issue template in the\n    ",[374,5630,5632],{"href":5631},"https://github.com/alvinunreal/openpets","OpenPets GitHub repo",";\n    open an issue with the required metadata and attach (or link to) the\n    spritesheet. Accepted pets are added to the catalog and become\n    installable from inside the desktop app.\n  ",{"title":244,"searchDepth":245,"depth":245,"links":5635},[5636,5637,5638,5639,5644,5645],{"id":5308,"depth":245,"text":5309},{"id":5345,"depth":245,"text":1841},{"id":5439,"depth":245,"text":5443},{"id":5468,"depth":245,"text":5469,"children":5640},[5641,5642,5643],{"id":5475,"depth":1196,"text":5476},{"id":5496,"depth":1196,"text":5497},{"id":5524,"depth":1196,"text":5525},{"id":5541,"depth":245,"text":5542},{"id":5624,"depth":245,"text":5625},"How OpenPets pet packages are structured — pet.json, spritesheet.webp, size limits, validation rules, and how to package a pet for the gallery.",{},"Pet format",80,{"title":176,"description":5646},"docs/pet-format",[5653,5654,5655,5656,5657,5658],{"id":5304,"label":5309},{"id":5341,"label":1841},{"id":5439,"label":5443},{"id":5464,"label":5469},{"id":5537,"label":5542},{"id":5017,"label":5625},"f9z5P6hhtbWbO9sU_hf8RH9BLmET4hZVABBExcNFZgM",{"id":5661,"title":5662,"body":5663,"description":5995,"extension":251,"meta":5996,"navTitle":5997,"navigation":253,"order":5998,"path":5999,"seo":6000,"stem":6001,"toc":6002,"__hash__":6011},"docs_en/docs/desktop-app.md","Desktop app behaviour",{"type":8,"value":5664,"toc":5985},[5665,5679,5829,5845,5867,5931,5946,5971],[11,5666,16,5669,16,5673,16,5676],{"id":5667,"className":5668},"tray-only",[15],[18,5670,5672],{"id":5671},"tray-only-design","Tray-only design",[22,5674,5675],{},"\n    OpenPets has no traditional main window. The app lives in your system\n    tray (Windows / Linux) or menu bar (macOS). On macOS, the app\n    deliberately hides itself from the Dock so the only visible presence is\n    your pet.\n  ",[22,5677,5678],{},"\n    Every action — managing pets, configuring integrations, changing\n    settings, quitting — is reached through the tray menu or one of the\n    short-lived \"task\" windows it opens.\n  ",[11,5680,16,5683,16,5686,16,16,5689],{"id":5681,"className":5682},"tray-menu",[15],[18,5684,5685],{"id":5681},"Tray menu",[22,5687,5688],{},"\n    The tray menu shows different items depending on app state. The full set\n    of items, in order:\n  ",[65,5690,69,5692,16],{"className":5691},[68],[71,5693,73,5694,73,5706,69],{},[75,5695,77,5696,73],{},[79,5697,5698,5701,5704],{},[82,5699,5700],{},"Item",[82,5702,5703],{},"Shows when",[82,5705,1338],{},[89,5707,77,5708,77,5720,77,5733,77,5746,77,5758,77,5770,77,5782,77,5793,77,5805,77,5817,73],{},[79,5709,5710,5714,5717],{},[94,5711,5712],{},[32,5713,1438],{},[94,5715,5716],{},"Always.",[94,5718,5719],{},"Disabled header label.",[79,5721,5722,5727,5730],{},[94,5723,5724],{},[32,5725,5726],{},"Update available...",[94,5728,5729],{},"A newer release exists on GitHub.",[94,5731,5732],{},"Opens the release page in your browser.",[79,5734,5735,5740,5743],{},[94,5736,5737],{},[32,5738,5739],{},"Continue Setup...",[94,5741,5742],{},"Onboarding was never completed.",[94,5744,5745],{},"Reopens the onboarding window.",[79,5747,5748,5753,5755],{},[94,5749,5750],{},[32,5751,5752],{},"Default Pet: ...",[94,5754,5716],{},[94,5756,5757],{},"Opens the Pet Manager. Shows the currently selected default pet's name.",[79,5759,5760,5765,5767],{},[94,5761,5762],{},[32,5763,5764],{},"Show / Hide Default Pet",[94,5766,5716],{},[94,5768,5769],{},"Toggles the default pet's window.",[79,5771,5772,5777,5779],{},[94,5773,5774],{},[32,5775,5776],{},"Pause / Resume All Pets",[94,5778,5716],{},[94,5780,5781],{},"Pauses all pet reactions and speech bubbles globally.",[79,5783,5784,5788,5790],{},[94,5785,5786],{},[32,5787,1696],{},[94,5789,5716],{},[94,5791,5792],{},"Opens Pet Manager.",[79,5794,5795,5800,5802],{},[94,5796,5797],{},[32,5798,5799],{},"Integrations...",[94,5801,5716],{},[94,5803,5804],{},"Opens the Integrations window.",[79,5806,5807,5812,5814],{},[94,5808,5809],{},[32,5810,5811],{},"Settings...",[94,5813,5716],{},[94,5815,5816],{},"Opens the Settings window.",[79,5818,5819,5824,5826],{},[94,5820,5821],{},[32,5822,5823],{},"Quit OpenPets",[94,5825,5716],{},[94,5827,5828],{},"Quits the app, releasing any active leases and removing the IPC discovery file.",[11,5830,16,5833,16,5836,16,5839,16,5842],{"id":5831,"className":5832},"pet-windows",[15],[18,5834,5835],{"id":5831},"Pet windows",[22,5837,5838],{},"\n    Each pet renders inside its own transparent, frameless, always-on-top\n    Electron window. The window has no chrome at all — it is just the\n    spritesheet with a transparent background and animation driven by CSS.\n  ",[22,5840,5841],{},"\n    The default pet uses one window that persists across the session. Agent\n    pets each get their own short-lived window that opens when an assistant\n    requests them and closes when the assistant stops.\n  ",[22,5843,5844],{},"\n    Pet windows track which screen they are on and remember their position\n    between launches.\n  ",[11,5846,16,5849,16,5853,16,5856],{"id":5847,"className":5848},"drag-and-clickthrough",[15],[18,5850,5852],{"id":5851},"drag-and-click-through","Drag and click-through",[22,5854,5855],{},"\n    You can drag any pet window around your desktop with the mouse. Outside\n    of dragging, the pet window is click-through by default, so it does not\n    intercept clicks meant for whatever is beneath it.\n  ",[22,5857,5858,5859,5862,5863,5866],{},"\n    The drag affordance and the click-through toggle are wired through a\n    small preload script that exposes a narrow renderer API via Electron's\n    ",[57,5860,5861],{},"contextBridge",". The renderer itself runs sandboxed with\n    context isolation, no Node integration, and a strict\n    ",[57,5864,5865],{},"default-src 'none'"," CSP.\n  ",[11,5868,16,5871,16,5874,16,5877],{"id":5869,"className":5870},"task-windows",[15],[18,5872,5873],{"id":5869},"Task windows",[22,5875,5876],{},"\n    Task windows are short-lived Electron windows opened from the tray menu.\n    They show a focused UI for one task and close when you are done.\n  ",[65,5878,69,5880,16],{"className":5879},[68],[71,5881,73,5882,73,5891,69],{},[75,5883,77,5884,73],{},[79,5885,5886,5889],{},[82,5887,5888],{},"Window",[82,5890,2278],{},[89,5892,77,5893,77,5902,77,5911,77,5921,73],{},[79,5894,5895,5899],{},[94,5896,5897],{},[32,5898,371],{},[94,5900,5901],{},"Browse the gallery, install or uninstall pets, pick the default pet.",[79,5903,5904,5908],{},[94,5905,5906],{},[32,5907,414],{},[94,5909,5910],{},"Install, configure, and remove Claude Code and OpenCode integrations.",[79,5912,5913,5918],{},[94,5914,5915],{},[32,5916,5917],{},"Settings",[94,5919,5920],{},"Adjust pet scale, speech-bubble preference, and other preferences.",[79,5922,5923,5928],{},[94,5924,5925],{},[32,5926,5927],{},"Onboarding",[94,5929,5930],{},"First-launch flow for choosing a starting pet and enabling startup display.",[11,5932,16,5935,16,5937,16,5940],{"id":5933,"className":5934},"onboarding",[15],[18,5936,5927],{"id":5933},[22,5938,5939],{},"\n    The first time OpenPets starts, the onboarding window opens\n    automatically. Once you finish (or skip) onboarding, the app marks it as\n    completed in your state file and stops showing the window at every\n    launch.\n  ",[22,5941,5942,5943,5945],{},"\n    If you skipped onboarding and want to come back to it, click\n    ",[32,5944,5739],{}," in the tray menu while the onboarding\n    state is still pending.\n  ",[11,5947,16,5950,16,5953,16,5960],{"id":5948,"className":5949},"update-checks",[15],[18,5951,5952],{"id":5948},"Update checks",[22,5954,5955,5956,5959],{},"\n    On startup, OpenPets queries the GitHub Releases API for the\n    ",[57,5957,5958],{},"alvinunreal/openpets"," repository to see whether a newer\n    version is available. The check runs once, in the background, with a\n    short timeout.\n  ",[22,5961,5962,5963,5966,5967,5970],{},"\n    If a newer version is found, the tray menu adds an\n    ",[32,5964,5965],{},"Update available"," entry that opens the release page in\n    your browser. Nothing is downloaded or installed automatically. See\n    ",[41,5968,1490],{"to":5969},"/docs/install#updates"," for the manual\n    update steps.\n  ",[11,5972,16,5975,16,5979,16,5982],{"id":5973,"className":5974},"single-instance",[15],[18,5976,5978],{"id":5977},"single-instance-behaviour","Single-instance behaviour",[22,5980,5981],{},"\n    OpenPets uses Electron's single-instance lock. If you launch the app\n    while it is already running, the second launch exits immediately and\n    the running instance brings its tray menu's most recent task window to\n    the front.\n  ",[22,5983,5984],{},"\n    This avoids accidental duplicate trays, duplicate IPC servers, and\n    duplicate update prompts.\n  ",{"title":244,"searchDepth":245,"depth":245,"links":5986},[5987,5988,5989,5990,5991,5992,5993,5994],{"id":5671,"depth":245,"text":5672},{"id":5681,"depth":245,"text":5685},{"id":5831,"depth":245,"text":5835},{"id":5851,"depth":245,"text":5852},{"id":5869,"depth":245,"text":5873},{"id":5933,"depth":245,"text":5927},{"id":5948,"depth":245,"text":5952},{"id":5977,"depth":245,"text":5978},"How the OpenPets tray app behaves — tray menu, pet windows, drag, click-through, task windows, onboarding, and update checks.",{},"Desktop app",90,"/docs/desktop-app",{"title":5662,"description":5995},"docs/desktop-app",[6003,6004,6005,6006,6007,6008,6009,6010],{"id":5667,"label":5672},{"id":5681,"label":5685},{"id":5831,"label":5835},{"id":5847,"label":5852},{"id":5869,"label":5873},{"id":5933,"label":5927},{"id":5948,"label":5952},{"id":5973,"label":5978},"jW1zgK_y2_8RVgrlrlCBCfZi1ZQFx3l-aSGn56w_JwI",{"id":6013,"title":1041,"body":6014,"description":6455,"extension":251,"meta":6456,"navTitle":198,"navigation":253,"order":6457,"path":197,"seo":6458,"stem":6459,"toc":6460,"__hash__":6468},"docs_en/docs/files-and-config.md",{"type":8,"value":6015,"toc":6446},[6016,6080,6124,6150,6231,6271,6363],[11,6017,16,6020,16,6024,16,6027,16,6069],{"id":6018,"className":6019},"user-data",[15],[18,6021,6023],{"id":6022},"user-data-directory","User data directory",[22,6025,6026],{},"\n    OpenPets keeps state, installed pets, and runtime metadata in a single\n    user data directory. The location is platform-specific.\n  ",[65,6028,69,6030,16],{"className":6029},[68],[71,6031,73,6032,73,6040,69],{},[75,6033,77,6034,73],{},[79,6035,6036,6038],{},[82,6037,289],{},[82,6039,909],{},[89,6041,77,6042,77,6050,77,6058,73],{},[79,6043,6044,6046],{},[94,6045,303],{},[94,6047,6048],{},[57,6049,1551],{},[79,6051,6052,6054],{},[94,6053,320],{},[94,6055,6056],{},[57,6057,1567],{},[79,6059,6060,6062],{},[94,6061,333],{},[94,6063,6064,4351,6067,1352],{},[57,6065,6066],{},"$XDG_CONFIG_HOME/OpenPets",[57,6068,1585],{},[22,6070,6071,6072,6075,6076,6079],{},"\n    You can override the path by setting ",[57,6073,6074],{},"OPENPETS_USER_DATA"," in\n    your environment. The override applies to the standalone installer and\n    to anything that uses the user data path; the desktop app itself uses\n    Electron's ",[57,6077,6078],{},"app.getPath(\"userData\")",", which respects its own\n    standard rules.\n  ",[11,6081,16,6084,16,6088,16,6095,16,6118],{"id":6082,"className":6083},"app-state",[15],[18,6085,6087],{"id":6086},"app-state-file","App state file",[22,6089,6090,6091,6094],{},"\n    The app state file ",[57,6092,6093],{},"openpets-state.json"," lives at the root of\n    the user data directory. It records:\n  ",[223,6096,69,6097,69,6100,69,6103,69,6106,69,6109,69,6112,69,6115,16],{},[226,6098,6099],{},"The selected default pet id.",[226,6101,6102],{},"Whether the default pet opens at launch and whether speech bubbles are enabled.",[226,6104,6105],{},"The pet scale preference.",[226,6107,6108],{},"Whether onboarding has been completed.",[226,6110,6111],{},"Optional command paths for Claude and OpenCode (if you set custom binaries).",[226,6113,6114],{},"The list of installed pets and their metadata.",[226,6116,6117],{},"The default pet's last-known position.",[22,6119,6120,6121,6123],{},"\n    All writes to ",[57,6122,6093],{}," are atomic: OpenPets\n    writes to a temporary file alongside the original and renames it into\n    place. There is no partial-write state.\n  ",[11,6125,16,6128,16,6132,16,6144],{"id":6126,"className":6127},"pet-directories",[15],[18,6129,6131],{"id":6130},"installed-pets","Installed pets",[22,6133,6134,6135,6137,6138,863,6140,6143],{},"\n    Each installed gallery pet lives under ",[57,6136,1802],{},".\n    The directory contains the extracted pet package — ",[57,6139,1841],{},[57,6141,6142],{},"spritesheet.webp",", and any optional preview image.\n  ",[22,6145,6146,6147,6149],{},"\n    Locally-developed Codex pets live separately under\n    ",[57,6148,1028],{},". The desktop app reads both\n    locations.\n  ",[11,6151,16,6154,16,6158,16,6165,16,6219,16,6228],{"id":6152,"className":6153},"discovery-file",[15],[18,6155,6157],{"id":6156},"ipc-discovery-file","IPC discovery file",[22,6159,6160,6161,820,6163,2227],{},"\n    When the desktop app starts, it writes a small JSON file that tells\n    clients (the MCP server, the CLI, hooks) where to connect and which\n    token to use. The file has permissions ",[57,6162,819],{},[57,6164,823],{},[65,6166,69,6168,16],{"className":6167},[68],[71,6169,73,6170,73,6179,69],{},[75,6171,77,6172,73],{},[79,6173,6174,6176],{},[82,6175,289],{},[82,6177,6178],{},"Discovery path",[89,6180,77,6181,77,6190,77,6199,77,6209,73],{},[79,6182,6183,6185],{},[94,6184,303],{},[94,6186,6187],{},[57,6188,6189],{},"~/Library/Application Support/OpenPets/runtime/ipc.json",[79,6191,6192,6194],{},[94,6193,320],{},[94,6195,6196],{},[57,6197,6198],{},"%APPDATA%\\OpenPets\\runtime\\ipc.json",[79,6200,6201,6204],{},[94,6202,6203],{},"Linux (secure XDG)",[94,6205,6206],{},[57,6207,6208],{},"$XDG_RUNTIME_DIR/openpets/ipc.json",[79,6210,6211,6214],{},[94,6212,6213],{},"Linux (fallback)",[94,6215,6216],{},[57,6217,6218],{},"~/.config/OpenPets/runtime/ipc.json",[22,6220,6221,6222,6224,6225,6227],{},"\n    On Linux, the secure XDG location is used only if\n    ",[57,6223,1460],{}," is a real directory you own with mode\n    ",[57,6226,823],{},". Otherwise OpenPets falls back to the path above.\n  ",[22,6229,6230],{},"\n    The discovery file contains a freshly-generated token every time the\n    desktop app starts. Old tokens become invalid immediately.\n  ",[11,6232,16,6235,16,6238],{"id":6233,"className":6234},"lock-files",[15],[18,6236,6237],{"id":6233},"Lock files",[223,6239,69,6240,69,6246,69,6259,16],{},[226,6241,6242,6245],{},[32,6243,6244],{},"Single-instance lock"," — Electron's built-in lock; held automatically while the desktop app is running.",[226,6247,6248,6251,6252,6254,6255,6258],{},[32,6249,6250],{},"Direct install lock"," — used by the standalone ",[57,6253,1766],{}," package to prevent two concurrent installs. Lives at ",[57,6256,6257],{},"\u003CuserData>/.install-pet.lock",". Stale locks are considered expired after 10 minutes.",[226,6260,6261,6264,6265,60,6267,6270],{},[32,6262,6263],{},"Unix socket"," — on macOS and Linux, the actual IPC socket file under ",[57,6266,1467],{},[57,6268,6269],{},"$XDG_RUNTIME_DIR/openpets/",". Removed when the app exits cleanly.",[11,6272,16,6275,16,6279,16,6285,16,6345,16,6354],{"id":6273,"className":6274},"claude-files",[15],[18,6276,6278],{"id":6277},"claude-managed-files","Claude-managed files",[22,6280,6281,6282,2352],{},"\n    When you install the Claude Code integration from the desktop app,\n    OpenPets manages three files under ",[57,6283,6284],{},"~/.claude/",[65,6286,69,6288,16],{"className":6287},[68],[71,6289,73,6290,73,6300,69],{},[75,6291,77,6292,73],{},[79,6293,6294,6297],{},[82,6295,6296],{},"File",[82,6298,6299],{},"What OpenPets writes",[89,6301,77,6302,77,6319,77,6333,73],{},[79,6303,300,6304,300,6308,77],{},[94,6305,6306],{},[57,6307,2081],{},[94,6309,6310,6311,6314,6315,6318],{},"One managed import block bracketed by ",[57,6312,6313],{},"\u003C!-- OPENPETS:IMPORT:START -->"," / ",[57,6316,6317],{},":END -->",". Existing instructions are preserved.",[79,6320,300,6321,300,6325,77],{},[94,6322,6323],{},[57,6324,2077],{},[94,6326,6327,6328,6314,6331,231],{},"The OpenPets instruction file itself, bracketed by ",[57,6329,6330],{},"\u003C!-- OPENPETS:START -->",[57,6332,6317],{},[79,6334,300,6335,300,6339,77],{},[94,6336,6337],{},[57,6338,2088],{},[94,6340,6341,6342,6344],{},"OpenPets-managed hook command entries (only when you opt in to hooks). Each managed command contains the ",[57,6343,2627],{}," marker.",[22,6346,6347,6348,6350,6351,6353],{},"\n    Claude's MCP config is written through the ",[57,6349,2614],{},"\n    command rather than by editing a file directly; the entry is named\n    ",[57,6352,444],{}," at user scope.\n  ",[22,6355,6356,6357,6359,6360,6362],{},"\n    Project-local Claude setup (via ",[57,6358,2114],{},") writes\n    to ",[57,6361,2620],{}," instead.\n  ",[11,6364,16,6367,16,6371,16,6378,16,6443],{"id":6365,"className":6366},"opencode-files",[15],[18,6368,6370],{"id":6369},"opencode-managed-files","OpenCode-managed files",[22,6372,6373,6374,6377],{},"\n    The OpenCode integration writes to OpenCode's global config directory,\n    typically ",[57,6375,6376],{},"~/.config/opencode/",". It manages three things\n    inside the OpenCode config file, plus a separate instructions file:\n  ",[65,6379,69,6381,16],{"className":6380},[68],[71,6382,73,6383,73,6392,69],{},[75,6384,77,6385,73],{},[79,6386,6387,6390],{},[82,6388,6389],{},"Where",[82,6391,6299],{},[89,6393,77,6394,77,6408,77,6418,77,6428,73],{},[79,6395,300,6396,300,6403,77],{},[94,6397,6398,6399,6402],{},"OpenCode config (",[57,6400,6401],{},"mcp"," section)",[94,6404,2608,6405,6407],{},[57,6406,444],{}," stdio MCP entry.",[79,6409,300,6410,300,6415,77],{},[94,6411,6398,6412,6414],{},[57,6413,4711],{}," array)",[94,6416,6417],{},"A reference to the OpenPets OpenCode plugin so it loads at editor startup.",[79,6419,300,6420,300,6425,77],{},[94,6421,6398,6422,6414],{},[57,6423,6424],{},"instructions",[94,6426,6427],{},"A reference to the OpenPets instructions file.",[79,6429,300,6430,300,6436,77],{},[94,6431,6432,6435],{},[57,6433,6434],{},".opencode/openpets.md"," (project) or the corresponding global path",[94,6437,6438,6439,6314,6441,231],{},"The OpenPets instructions, bracketed by ",[57,6440,6330],{},[57,6442,6317],{},[22,6444,6445],{},"\n    OpenCode config edits use a JSONC parser so existing comments and\n    trailing commas survive. Writes are atomic with backups. The\n    integration refuses to write through symlinks.\n  ",{"title":244,"searchDepth":245,"depth":245,"links":6447},[6448,6449,6450,6451,6452,6453,6454],{"id":6022,"depth":245,"text":6023},{"id":6086,"depth":245,"text":6087},{"id":6130,"depth":245,"text":6131},{"id":6156,"depth":245,"text":6157},{"id":6233,"depth":245,"text":6237},{"id":6277,"depth":245,"text":6278},{"id":6369,"depth":245,"text":6370},"Every file OpenPets reads or writes on your machine — user data, state, installed pets, discovery file, locks, and the files OpenPets manages inside Claude and OpenCode configs.",{},100,{"title":1041,"description":6455},"docs/files-and-config",[6461,6462,6463,6464,6465,6466,6467],{"id":6018,"label":6023},{"id":6082,"label":6087},{"id":6126,"label":6131},{"id":6152,"label":6157},{"id":6233,"label":6237},{"id":6273,"label":6278},{"id":6365,"label":6370},"VKFwBKZsA_O69U0c9adaFlNu3yEMh9SxLVQ8CQbjrOk",{"id":6470,"title":399,"body":6471,"description":6736,"extension":251,"meta":6737,"navTitle":203,"navigation":253,"order":6738,"path":202,"seo":6739,"stem":6740,"toc":6741,"__hash__":6748},"docs_en/docs/privacy.md",{"type":8,"value":6472,"toc":6728},[6473,6487,6606,6616,6678,6699],[11,6474,16,6477,16,6481,16,6484],{"id":6475,"className":6476},"local-first",[15],[18,6478,6480],{"id":6479},"local-first-by-design","Local-first by design",[22,6482,6483],{},"\n    OpenPets runs entirely on your machine. The desktop app, the MCP server,\n    the CLI, and every assistant integration talk to each other over a\n    local socket — never the network. There is no cloud backend, no\n    OpenPets account, no remote orchestration.\n  ",[22,6485,6486],{},"\n    The only outbound network traffic OpenPets ever makes is the small set\n    of HTTPS calls listed below.\n  ",[11,6488,16,6491,16,6494,16,6603],{"id":6489,"className":6490},"network-calls",[15],[18,6492,6493],{"id":6489},"Network calls",[65,6495,69,6497,16],{"className":6496},[68],[71,6498,73,6499,73,6512,69],{},[75,6500,77,6501,73],{},[79,6502,6503,6506,6509],{},[82,6504,6505],{},"Endpoint",[82,6507,6508],{},"When",[82,6510,6511],{},"Why",[89,6513,77,6514,77,6526,77,6539,77,6551,77,6564,77,6577,77,6590,73],{},[79,6515,300,6516,300,6520,300,6523,77],{},[94,6517,6518],{},[57,6519,1637],{},[94,6521,6522],{},"When you open the Pet Manager or run a CLI install.",[94,6524,6525],{},"To fetch the pet catalog so you can browse and install pets.",[79,6527,300,6528,300,6533,300,6536,77],{},[94,6529,6530],{},[57,6531,6532],{},"https://zip.openpets.dev/pets/\u003Cpet-id>.zip",[94,6534,6535],{},"When you install a specific pet.",[94,6537,6538],{},"To download that pet's package.",[79,6540,300,6541,300,6545,300,6548,77],{},[94,6542,6543],{},[57,6544,5028],{},[94,6546,6547],{},"When you open the Plugins panel.",[94,6549,6550],{},"To fetch the plugin catalog so you can install or update approved plugins.",[79,6552,300,6553,300,6558,300,6561,77],{},[94,6554,6555],{},[57,6556,6557],{},"https://zip.openpets.dev/plugins/\u003Cplugin-id>.zip",[94,6559,6560],{},"When you install or update a plugin.",[94,6562,6563],{},"To download that plugin's package.",[79,6565,300,6566,300,6571,300,6574,77],{},[94,6567,6568],{},[57,6569,6570],{},"https://openpets.dev/pets/\u003Cpet-id>/preview.webp",[94,6572,6573],{},"When the gallery is open.",[94,6575,6576],{},"To render the pet's thumbnail.",[79,6578,300,6579,300,6584,300,6587,77],{},[94,6580,6581],{},[57,6582,6583],{},"https://api.github.com/repos/alvinunreal/openpets/releases",[94,6585,6586],{},"Once at startup, with a short timeout.",[94,6588,6589],{},"To check whether a newer OpenPets release exists. Nothing is downloaded automatically.",[79,6591,300,6592,300,6597,300,6600,77],{},[94,6593,6594],{},[57,6595,6596],{},"https://api.github.com/repos/\u003Cowner>/\u003Crepo>",[94,6598,6599],{},"Only when the GitHub Notifications plugin is enabled and configured with public repositories.",[94,6601,6602],{},"To check visible public repository activity. The plugin does not use OAuth, tokens, or private repository access.",[22,6604,6605],{},"\n    Catalog URLs that do not point at approved OpenPets catalog and ZIP hosts\n    are rejected by the validator before\n    any request is made. The catalog is also rejected if it tries to embed\n    credentials, custom ports, or non-HTTPS URLs.\n  ",[11,6607,16,6610,16,6613],{"id":6608,"className":6609},"no-telemetry",[15],[18,6611,6612],{"id":6608},"No telemetry",[22,6614,6615],{},"\n    OpenPets does not collect usage analytics, crash reports, or any other\n    telemetry. There is no opt-out toggle because there is nothing to\n    disable. The desktop app makes only the calls listed above\n    and nothing else.\n  ",[11,6617,16,6620,16,6622,16,6628,16,6675],{"id":6618,"className":6619},"speech-validation",[15],[18,6621,3448],{"id":6618},[22,6623,6624,6625,6627],{},"\n    OpenPets is designed as a benign visible-status channel, not a\n    transcript sink. Every ",[57,6626,515],{}," message goes through a\n    server-side validator that rejects anything that looks like sensitive\n    or accidentally-leaked content.\n  ",[223,6629,69,6630,69,6633,69,6650,69,6661,69,6664,16],{},[226,6631,6632],{},"1–140 characters, single line.",[226,6634,6635,6636,859,6639,859,6641,859,6643,859,6645,859,6648,2438],{},"No code-like content (backticks, ",[57,6637,6638],{},"function",[57,6640,3360],{},[57,6642,3363],{},[57,6644,3366],{},[57,6646,6647],{},"=>",[57,6649,3356],{},[226,6651,6652,6653,859,6656,859,6659,2438],{},"No URLs (",[57,6654,6655],{},"http://",[57,6657,6658],{},"https://",[57,6660,3372],{},[226,6662,6663],{},"No file paths (slash paths, Windows drive letters).",[226,6665,6666,6667,859,6669,859,6671,859,6673,3389],{},"No secret-like words (",[57,6668,3379],{},[57,6670,3382],{},[57,6672,3385],{},[57,6674,3388],{},[22,6676,6677],{},"\n    The validator runs inside the MCP server, before the message is sent to\n    the desktop app. Even if an assistant ignores its instructions, a bad\n    message is rejected with a plain error.\n  ",[11,6679,16,6682,16,6686,16,6689],{"id":6680,"className":6681},"keychain",[15],[18,6683,6685],{"id":6684},"why-openpets-avoids-the-keychain","Why OpenPets avoids the keychain",[22,6687,6688],{},"\n    On macOS and Linux, Chromium (which Electron uses) tries to access the\n    OS credential store at startup to encrypt browser-style passwords and\n    cookies. OpenPets stores none of those, so the credential prompt would\n    be confusing.\n  ",[22,6690,6691,6692,35,6695,6698],{},"\n    The app passes two startup flags to Chromium —\n    ",[57,6693,6694],{},"--use-mock-keychain",[57,6696,6697],{},"--password-store=basic"," —\n    to disable that behaviour. OpenPets does not have a Keychain entry,\n    does not request one, and does not need one.\n  ",[11,6700,16,6703,16,6706,16,6709,16,6725],{"id":6701,"className":6702},"tokens-and-sockets",[15],[18,6704,6705],{"id":6701},"Tokens and sockets",[22,6707,6708],{},"\n    The local IPC is gated by a token written to a private discovery file.\n    Each desktop app startup generates a new random 32-byte token. Old\n    tokens stop working immediately on restart.\n  ",[223,6710,69,6711,69,6719,69,6722,16],{},[226,6712,6713,6714,6716,6717,231],{},"On macOS and Linux, the IPC socket and the discovery file live inside ",[57,6715,823],{}," directories and are themselves ",[57,6718,819],{},[226,6720,6721],{},"On Windows, the named pipe is scoped to the current user session.",[226,6723,6724],{},"Other users on the same machine cannot connect to your OpenPets without your token.",[22,6726,6727],{},"\n    Tool errors that bubble up to the MCP client are sanitized — IPC paths,\n    socket names, tokens, and low-level system error codes are stripped\n    before they ever reach the assistant.\n  ",{"title":244,"searchDepth":245,"depth":245,"links":6729},[6730,6731,6732,6733,6734,6735],{"id":6479,"depth":245,"text":6480},{"id":6489,"depth":245,"text":6493},{"id":6608,"depth":245,"text":6612},{"id":6618,"depth":245,"text":3448},{"id":6684,"depth":245,"text":6685},{"id":6701,"depth":245,"text":6705},"Exactly what OpenPets sends, where, and why — and what it doesn't. No telemetry, local-first IPC, validated speech.",{},110,{"title":399,"description":6736},"docs/privacy",[6742,6743,6744,6745,6746,6747],{"id":6475,"label":6480},{"id":6489,"label":6493},{"id":6608,"label":6612},{"id":6618,"label":3448},{"id":6680,"label":6685},{"id":6701,"label":6705},"OBnV3BQ4tcVtnEwQsFx6L9AMfb4aZCE4iU_8C35kyVQ",{"id":6750,"title":214,"body":6751,"description":7013,"extension":251,"meta":7014,"navTitle":214,"navigation":253,"order":7015,"path":213,"seo":7016,"stem":7017,"toc":7018,"__hash__":7027},"docs_en/docs/troubleshooting.md",{"type":8,"value":6752,"toc":7003},[6753,6775,6819,6838,6859,6903,6943,6969],[11,6754,16,6757,16,6761,16,6764],{"id":6755,"className":6756},"app-not-running",[15],[18,6758,6760],{"id":6759},"the-desktop-app-is-not-running","The desktop app is not running",[22,6762,6763],{},"\n    Most \"OpenPets is unavailable\" errors mean the desktop app is closed or\n    crashed.\n  ",[223,6765,69,6766,69,6769,69,6772,16],{},[226,6767,6768],{},"Check the system tray (or menu bar on macOS) for the OpenPets icon.",[226,6770,6771],{},"If the icon is missing, launch the app again. The single-instance lock will route a second launch to the existing one if it is still running.",[226,6773,6774],{},"If you see the icon but tools still fail, the discovery token may have rotated. Restart your MCP client so it acquires a fresh lease.",[11,6776,16,6779,16,6783],{"id":6777,"className":6778},"claude-no-tools",[15],[18,6780,6782],{"id":6781},"claude-does-not-show-openpets-tools","Claude does not show OpenPets tools",[1261,6784,69,6785,69,6788,69,6798,69,6810,16],{},[226,6786,6787],{},"Restart Claude Code after installing or replacing the MCP configuration.",[226,6789,6790,6791,6793,6794,6797],{},"In OpenPets, open ",[32,6792,414],{}," and click ",[32,6795,6796],{},"Refresh"," on the Claude card.",[226,6799,6800,6801,6803,6804,6806,6807,231],{},"Run ",[57,6802,2686],{}," in a terminal. The CLI must be on ",[57,6805,2347],{}," for OpenPets to detect Claude. If it lives elsewhere, set a full path under ",[32,6808,6809],{},"Advanced detection",[226,6811,6812,6813,35,6816,231],{},"Verify the MCP entry with ",[57,6814,6815],{},"claude mcp list",[57,6817,6818],{},"claude mcp get openpets",[11,6820,16,6823,16,6827],{"id":6821,"className":6822},"opencode-no-react",[15],[18,6824,6826],{"id":6825},"opencode-does-not-react","OpenCode does not react",[223,6828,69,6829,69,6832,69,6835,16],{},[226,6830,6831],{},"Make sure OpenPets is running. The OpenCode plugin uses the same local IPC, so a closed desktop app means no reactions.",[226,6833,6834],{},"Confirm the OpenPets plugin entry is still listed in your OpenCode config. The Integrations window can re-add it if it was removed.",[226,6836,6837],{},"Reactions are throttled. If you have already seen one reaction recently, the next event may be silenced — this is intentional and not a bug.",[11,6839,16,6842,16,6846,16,6852],{"id":6840,"className":6841},"mcp-custom-entry",[15],[18,6843,6845],{"id":6844},"mcp-entry-is-reported-as-custom","MCP entry is reported as custom",[22,6847,6848,6849,6851],{},"\n    \"Custom\" means Claude (or OpenCode) already has a server named\n    ",[57,6850,444],{}," but its command does not match what OpenPets would\n    write today. OpenPets leaves it alone in that case to avoid stomping on\n    your customization.\n  ",[22,6853,6854,6855,6858],{},"\n    To force OpenPets to recreate the entry, open the integration card and\n    click ",[32,6856,6857],{},"Replace configuration",". Your previous custom\n    command will be overwritten.\n  ",[11,6860,16,6863,16,6867],{"id":6861,"className":6862},"pet-install-fails",[15],[18,6864,6866],{"id":6865},"a-pet-fails-to-install","A pet fails to install",[223,6868,69,6869,69,6874,69,6880,69,6888,69,6897,16],{},[226,6870,6871,6872,231],{},"Check the pet id. Lowercase letters, digits, hyphens, underscores; up to 64 characters; cannot be ",[57,6873,1964],{},[226,6875,6876,6877,6879],{},"Make sure the pet exists in the gallery. Open ",[374,6878,377],{"href":376}," and verify the id.",[226,6881,6882,6883,35,6886,231],{},"Check your network. The catalog and ZIP downloads require HTTPS access to ",[57,6884,6885],{},"openpets.dev",[57,6887,1710],{},[226,6889,6890,6891,6893,6894,6896],{},"If the standalone ",[57,6892,1766],{}," reports a stale lock, wait 10 minutes for the lock to expire or remove ",[57,6895,6257],{}," by hand after confirming no other install is running.",[226,6898,6899,6900,6902],{},"Validation can reject malformed pets. The error message names the rule that failed — symlinks, oversized files, missing ",[57,6901,1841],{},", missing spritesheet, etc.",[11,6904,16,6907,16,6911],{"id":6905,"className":6906},"pet-not-showing",[15],[18,6908,6910],{"id":6909},"the-pet-is-not-showing","The pet is not showing",[223,6912,69,6913,69,6924,69,6931,69,6940,16],{},[226,6914,6915,6916,6919,6920,6923],{},"From the tray menu, check ",[32,6917,6918],{},"Show Default Pet",". If it reads ",[32,6921,6922],{},"Hide Default Pet",", the pet is already shown — look at other monitors.",[226,6925,6926,6927,6930],{},"If pets are paused (",[32,6928,6929],{},"Resume All Pets"," in the tray menu), unpause them.",[226,6932,6933,6934,6936,6937,6939],{},"If you requested a specific pet via ",[57,6935,2173],{},", look at the structured status response. A ",[57,6938,3512],{}," means the pet is missing or broken and events went to the default instead.",[226,6941,6942],{},"Reinstall the affected pet from the Pet Manager.",[11,6944,16,6947,16,6951,16,6957],{"id":6945,"className":6946},"update-fails",[15],[18,6948,6950],{"id":6949},"update-check-fails","Update check fails",[22,6952,6953,6954,6956],{},"\n    The update check hits the GitHub Releases API and times out quickly if\n    your network is slow or restricted. A failed check is non-fatal — the\n    tray menu simply omits the ",[32,6955,5965],{}," entry.\n  ",[223,6958,69,6959,69,6962,16],{},[226,6960,6961],{},"If you suspect you are out of date, visit the OpenPets GitHub releases page directly.",[226,6963,6964,6965,6968],{},"Corporate networks sometimes block ",[57,6966,6967],{},"api.github.com",". The check will fail silently if so.",[11,6970,16,6973,16,6977,16,6984,16,7000],{"id":6971,"className":6972},"reporting",[15],[18,6974,6976],{"id":6975},"reporting-an-issue","Reporting an issue",[22,6978,6979,6980,6983],{},"\n    If something is still broken after walking through this page, please\n    open an issue at the\n    ",[374,6981,5632],{"href":6982},"https://github.com/alvinunreal/openpets/issues",".\n    Include:\n  ",[223,6985,69,6986,69,6989,69,6992,69,6995,16],{},[226,6987,6988],{},"Your operating system and OpenPets app version (visible in the Settings window).",[226,6990,6991],{},"The exact steps to reproduce.",[226,6993,6994],{},"Which assistant and integration are involved (Claude Code, OpenCode, etc.).",[226,6996,6997,6998,231],{},"For hook problems, the output of running the hook command with ",[57,6999,2876],{},[22,7001,7002],{},"\n    Please do not paste private code, secrets, or full transcripts into\n    issues. A short error message and the steps to reproduce are usually\n    enough.\n  ",{"title":244,"searchDepth":245,"depth":245,"links":7004},[7005,7006,7007,7008,7009,7010,7011,7012],{"id":6759,"depth":245,"text":6760},{"id":6781,"depth":245,"text":6782},{"id":6825,"depth":245,"text":6826},{"id":6844,"depth":245,"text":6845},{"id":6865,"depth":245,"text":6866},{"id":6909,"depth":245,"text":6910},{"id":6949,"depth":245,"text":6950},{"id":6975,"depth":245,"text":6976},"Common OpenPets problems and how to fix them — desktop app, integrations, MCP, hooks, pet installs, and reporting issues.",{},120,{"title":214,"description":7013},"docs/troubleshooting",[7019,7020,7021,7022,7023,7024,7025,7026],{"id":6755,"label":6760},{"id":6777,"label":6782},{"id":6821,"label":6826},{"id":6840,"label":6845},{"id":6861,"label":6866},{"id":6905,"label":6910},{"id":6945,"label":6950},{"id":6971,"label":6976},"c9TcPB6OYetLJiRx7o8ZA992Ln31SE8mEJ26llAjoN4",{"id":7029,"title":5235,"body":7030,"description":7481,"extension":251,"meta":7482,"navTitle":7483,"navigation":253,"order":7484,"path":5234,"seo":7485,"stem":7486,"toc":7487,"__hash__":7496},"docs_en/docs/developer.md",{"type":8,"value":7031,"toc":7471},[7032,7065,7101,7243,7269,7341,7408,7433],[11,7033,16,7036,16,7040,16,7043,16,7058],{"id":7034,"className":7035},"repo-layout",[15],[18,7037,7039],{"id":7038},"repository-layout","Repository layout",[22,7041,7042],{},"\n    OpenPets is a pnpm workspace with two top-level workspace patterns: one\n    for deployable apps and one for publishable packages.\n  ",[65,7044,69,7046,69,7053,16],{"className":7045},[485],[65,7047,7049,7051],{"className":7048},[489],[491,7050,1825],{},[491,7052,496],{},[498,7054,7055],{},[57,7056,7057],{},"openpets/\n├── apps/\n│   └── desktop/        # Electron tray app\n├── packages/\n│   ├── agent-events/   # Speech pools + validation\n│   ├── claude/         # Claude Code integration\n│   ├── cli/            # `openpets` CLI\n│   ├── client/         # Local IPC client\n│   ├── install-pet/    # Standalone pet installer\n│   ├── mcp/            # MCP server\n│   ├── opencode/       # OpenCode integration\n│   └── pet-format/     # Pet package marker type\n└── web/                # openpets.dev (Nuxt 4)",[22,7059,7060,7061,7064],{},"\n    Every workspace package is ESM (",[57,7062,7063],{},"\"type\": \"module\"",") and\n    written in TypeScript 6, targeting Node ≥ 20.\n  ",[11,7066,16,7069,16,7072,16,7075,16,7090],{"id":7067,"className":7068},"setup",[15],[18,7070,7071],{"id":7067},"Setup",[22,7073,7074],{},"\n    Install pnpm 11 and Node 20+, then:\n  ",[65,7076,69,7078,69,7085,16],{"className":7077},[485],[65,7079,7081,7083],{"className":7080},[489],[491,7082,1303],{},[491,7084,1306],{},[498,7086,7087],{},[57,7088,7089],{},"pnpm install\npnpm build       # build all workspace packages\npnpm dev:desktop # run the desktop app in dev mode",[22,7091,7092,7093,7096,7097,7100],{},"\n    The desktop app depends on the workspace packages via\n    ",[57,7094,7095],{},"workspace:*",", so a fresh build of the packages is required\n    before ",[57,7098,7099],{},"dev:desktop"," can launch it.\n  ",[11,7102,16,7104,16,7108],{"id":4616,"className":7103},[15],[18,7105,7107],{"id":7106},"common-commands","Common commands",[65,7109,69,7111,16],{"className":7110},[68],[71,7112,73,7113,73,7121,69],{},[75,7114,77,7115,73],{},[79,7116,7117,7119],{},[82,7118,2275],{},[82,7120,1338],{},[89,7122,77,7123,77,7133,77,7147,77,7160,77,7177,77,7187,77,7196,77,7209,77,7223,77,7233,73],{},[79,7124,7125,7130],{},[94,7126,7127],{},[57,7128,7129],{},"pnpm build",[94,7131,7132],{},"Build every workspace package.",[79,7134,7135,7140],{},[94,7136,7137],{},[57,7138,7139],{},"pnpm check",[94,7141,7142,7143,7146],{},"Run each package's ",[57,7144,7145],{},"check"," script (lint, format, etc.).",[79,7148,7149,7154],{},[94,7150,7151],{},[57,7152,7153],{},"pnpm typecheck",[94,7155,7142,7156,7159],{},[57,7157,7158],{},"typecheck"," script.",[79,7161,7162,7167],{},[94,7163,7164],{},[57,7165,7166],{},"pnpm test",[94,7168,7169,7170,7173,7174,2438],{},"Build, then run each package's ",[57,7171,7172],{},"test"," script (contract checks live alongside source as ",[57,7175,7176],{},"check-*.ts",[79,7178,7179,7184],{},[94,7180,7181],{},[57,7182,7183],{},"pnpm dev:desktop",[94,7185,7186],{},"Run the Electron desktop app in development.",[79,7188,7189,7193],{},[94,7190,7191],{},[57,7192,4987],{},[94,7194,7195],{},"Run the desktop app with local plugin development support.",[79,7197,7198,7203],{},[94,7199,7200],{},[57,7201,7202],{},"pnpm package:desktop:dir",[94,7204,7205,7206,231],{},"Produce an unpacked desktop build at ",[57,7207,7208],{},"apps/desktop/dist-electron/",[79,7210,7211,7216],{},[94,7212,7213],{},[57,7214,7215],{},"pnpm package:desktop",[94,7217,7218,7219,7222],{},"Run the full ",[57,7220,7221],{},"electron-builder"," packaging for your current platform.",[79,7224,7225,7230],{},[94,7226,7227],{},[57,7228,7229],{},"pnpm release:desktop",[94,7231,7232],{},"Orchestrate a local multi-platform release (see below).",[79,7234,7235,7240],{},[94,7236,7237],{},[57,7238,7239],{},"pnpm release:npm",[94,7241,7242],{},"Publish workspace packages to npm.",[11,7244,16,7246,16,7249,16,7255],{"id":1130,"className":7245},[15],[18,7247,7248],{"id":1130},"Testing",[22,7250,7251,7252,7254],{},"\n    OpenPets uses lightweight contract-style tests rather than a heavy test\n    framework. Every package has one or more ",[57,7253,7176],{}," files\n    that exercise the package's public surface end-to-end and assert\n    expected behaviour.\n  ",[223,7256,69,7257,69,7263,69,7266,16],{},[226,7258,7259,7260,7262],{},"Contract files run during ",[57,7261,7166],{}," at the workspace root.",[226,7264,7265],{},"The checks intentionally cover the IPC protocol, lease lifecycle, ZIP safety, catalog validation, and other boundary modules.",[226,7267,7268],{},"They are deliberately fast and deterministic — there is no network, no Electron startup, and no test runner harness.",[11,7270,16,7273,16,7277,16,7283,16,7299,16,7302,16,7305,16,7320,16,7323,16,7338],{"id":7271,"className":7272},"plugins",[15],[18,7274,7276],{"id":7275},"plugin-development","Plugin development",[22,7278,7279,7280,7282],{},"\n    Desktop plugins use manifest v2 and a bundled JavaScript entry file. The\n    manifest declares the plugin id, version, entry point, configuration\n    schema, permissions, and approved HTTPS hosts. At runtime the entry calls\n    ",[57,7281,3907],{}," so the desktop app can\n    start and stop it cleanly.\n  ",[65,7284,69,7286,69,7294,16],{"className":7285},[485],[65,7287,7289,7292],{"className":7288},[489],[491,7290,7291],{},"Plugin entry",[491,7293,4118],{},[498,7295,7296],{},[57,7297,7298],{},"OpenPetsPlugin.register({\n  async start(ctx) {\n    await ctx.pet.say('Plugin started')\n  },\n  async stop(ctx) {\n    await ctx.pet.react('idle')\n  },\n})",[22,7300,7301],{},"\n    The SDK exposes the supported plugin surface: pet speech and reactions,\n    configuration reads, timers, logging, and HTTPS requests to hosts approved\n    by the manifest. Plugins do not get Node APIs, shell execution, direct\n    filesystem access, or arbitrary networking.\n  ",[22,7303,7304],{},"\n    For local development, point the desktop app at plugin folders or manifest\n    files before launching it:\n  ",[65,7306,69,7308,69,7315,16],{"className":7307},[485],[65,7309,7311,7313],{"className":7310},[489],[491,7312,1303],{},[491,7314,1306],{},[498,7316,7317],{},[57,7318,7319],{},"OPENPETS_DEV_PLUGIN_ROOTS=/path/to/plugin-root pnpm dev:desktop:plugins\nOPENPETS_DEV_PLUGIN_PATHS=/path/to/openpets.plugin.json pnpm dev:desktop:plugins",[22,7321,7322],{},"\n    Before submitting catalog changes, run the root plugin checks and stage\n    local catalog artifacts without uploading ZIP files:\n  ",[65,7324,69,7326,69,7333,16],{"className":7325},[485],[65,7327,7329,7331],{"className":7328},[489],[491,7330,1303],{},[491,7332,1306],{},[498,7334,7335],{},[57,7336,7337],{},"pnpm plugins:test\npnpm plugins:check\npnpm plugins:package",[22,7339,7340],{},"\n    Safety limits are part of the contract: no Node, shell, or filesystem\n    access; HTTPS only; and host allowlisting enforced through the SDK.\n  ",[11,7342,16,7345,16,7349,16,7356,16,7359,16,7396],{"id":7343,"className":7344},"release-desktop",[15],[18,7346,7348],{"id":7347},"release-desktop-app","Release: desktop app",[22,7350,7351,7352,7355],{},"\n    Desktop releases are produced from macOS by a single orchestrator\n    script at ",[57,7353,7354],{},"apps/desktop/scripts/release-local.mjs",". It\n    runs preflight checks, builds, and produces installers for macOS,\n    Windows, and Linux from one machine.\n  ",[22,7357,7358],{},"\n    Default build plan:\n  ",[65,7360,69,7362,16],{"className":7361},[68],[71,7363,73,7364,73,7373,69],{},[75,7365,77,7366,73],{},[79,7367,7368,7370],{},[82,7369,289],{},[82,7371,7372],{},"Default artifact",[89,7374,77,7375,77,7382,77,7389,73],{},[79,7376,7377,7379],{},[94,7378,303],{},[94,7380,7381],{},"DMG (universal x64 + arm64)",[79,7383,7384,7386],{},[94,7385,320],{},[94,7387,7388],{},"NSIS installer (x64)",[79,7390,7391,7393],{},[94,7392,333],{},[94,7394,7395],{},"AppImage (x64)",[22,7397,7398,7399,7401,7402,7404,7405,7407],{},"\n    Optional flags add a macOS ZIP, a Windows portable executable, Linux\n    ",[57,7400,341],{}," or tarball builds, or experimental ARM64 builds for\n    Windows and Linux. After build, the script generates a\n    ",[57,7403,1248],{}," file and, with ",[57,7406,2549],{},", creates a\n    GitHub draft release and uploads the artifacts.\n  ",[11,7409,16,7412,16,7416,16,7422],{"id":7410,"className":7411},"release-npm",[15],[18,7413,7415],{"id":7414},"release-npm-packages","Release: npm packages",[22,7417,7418,7419,7421],{},"\n    Workspace packages are published independently. Run\n    ",[57,7420,7239],{}," from the repo root; the orchestrator\n    builds, runs checks, and publishes each package whose version has\n    changed since its last publish.\n  ",[22,7423,7424,7425,7428,7429,7432],{},"\n    All packages currently share the ",[57,7426,7427],{},"2.0.x"," version line but\n    have independent ",[57,7430,7431],{},"package.json"," versions, so you can bump\n    one without rev'ing the rest.\n  ",[11,7434,16,7437,16,7441,16,7444,16,7464],{"id":7435,"className":7436},"architecture",[15],[18,7438,7440],{"id":7439},"where-to-read-next","Where to read next",[22,7442,7443],{},"\n    The internal architecture is documented through per-directory codemap\n    files inside the repository. They are intended for contributors, not\n    end users:\n  ",[223,7445,69,7446,69,7452,69,7458,16],{},[226,7447,7448,7451],{},[57,7449,7450],{},"codemap.md"," at the repo root for a high-level workspace map.",[226,7453,7454,7457],{},[57,7455,7456],{},"apps/desktop/src/codemap.md"," for the Electron app's module layout.",[226,7459,7460,7463],{},[57,7461,7462],{},"packages/\u003Cname>/src/codemap.md"," for each package's responsibilities.",[22,7465,7466,7467,378],{},"\n    For the public-facing surface of every package, see\n    ",[41,7468,7470],{"to":7469},"/docs/packages","Package reference",{"title":244,"searchDepth":245,"depth":245,"links":7472},[7473,7474,7475,7476,7477,7478,7479,7480],{"id":7038,"depth":245,"text":7039},{"id":7067,"depth":245,"text":7071},{"id":7106,"depth":245,"text":7107},{"id":1130,"depth":245,"text":7248},{"id":7275,"depth":245,"text":7276},{"id":7347,"depth":245,"text":7348},{"id":7414,"depth":245,"text":7415},{"id":7439,"depth":245,"text":7440},"Build, test, package, and release OpenPets. Workspace layout, scripts, and where to look in the codebase.",{},"Developer",130,{"title":5235,"description":7481},"docs/developer",[7488,7489,7490,7491,7492,7493,7494,7495],{"id":7034,"label":7039},{"id":7067,"label":7071},{"id":4616,"label":7107},{"id":1130,"label":7248},{"id":7271,"label":7276},{"id":7343,"label":7348},{"id":7410,"label":7415},{"id":7435,"label":7440},"9kV0X9dsMlwL3odQE9cJn5fa_IB90cpOe-zY4H_OWWU",{"id":7498,"title":7470,"body":7499,"description":7916,"extension":251,"meta":7917,"navTitle":7918,"navigation":253,"order":7919,"path":7469,"seo":7920,"stem":7921,"toc":7922,"__hash__":7932},"docs_en/docs/packages.md",{"type":8,"value":7500,"toc":7905},[7501,7609,7679,7709,7737,7782,7819,7860,7888],[11,7502,16,7504,16,7506,16,7512],{"id":1997,"className":7503},[15],[18,7505,2001],{"id":1997},[22,7507,7508,7509,7511],{},"\n    OpenPets is split into small focused npm packages so integrations and\n    third-party tools can depend on only the pieces they need. Inside the\n    monorepo they are linked via ",[57,7510,7095],{},"; on npm they are\n    independently versioned.\n  ",[65,7513,69,7515,16],{"className":7514},[68],[71,7516,73,7517,73,7527,69],{},[75,7518,77,7519,73],{},[79,7520,7521,7524],{},[82,7522,7523],{},"Package",[82,7525,7526],{},"Use when…",[89,7528,77,7529,77,7539,77,7551,77,7560,77,7570,77,7580,77,7590,77,7599,73],{},[79,7530,7531,7536],{},[94,7532,7533],{},[57,7534,7535],{},"@open-pets/client",[94,7537,7538],{},"You want to talk to the OpenPets desktop app directly from Node.",[79,7540,7541,7545],{},[94,7542,7543],{},[57,7544,2340],{},[94,7546,7547,7548,7550],{},"You want the ",[57,7549,444],{}," CLI for installs, configure, MCP, and hooks.",[79,7552,7553,7557],{},[94,7554,7555],{},[57,7556,2702],{},[94,7558,7559],{},"You want the OpenPets MCP server as a standalone binary.",[79,7561,7562,7567],{},[94,7563,7564],{},[57,7565,7566],{},"@open-pets/claude",[94,7568,7569],{},"You are building a Claude Code integration or running Claude hooks programmatically.",[79,7571,7572,7577],{},[94,7573,7574],{},[57,7575,7576],{},"@open-pets/opencode",[94,7578,7579],{},"You are building an OpenCode plugin or managing OpenCode configs.",[79,7581,7582,7587],{},[94,7583,7584],{},[57,7585,7586],{},"@open-pets/agent-events",[94,7588,7589],{},"You need the shared speech pools and validator without the rest of the stack.",[79,7591,7592,7596],{},[94,7593,7594],{},[57,7595,1766],{},[94,7597,7598],{},"You need a zero-dep CLI to install a pet without the OpenPets desktop app.",[79,7600,7601,7606],{},[94,7602,7603],{},[57,7604,7605],{},"@open-pets/pet-format",[94,7607,7608],{},"You want a type-level marker for OpenPets-compatible pet packages.",[11,7610,16,7613,16,7618,16,7621,16,7664],{"id":7611,"className":7612},"client",[15],[18,7614,7616],{"id":7615},"open-petsclient",[57,7617,7535],{},[22,7619,7620],{},"\n    The core IPC client. Every other OpenPets package that talks to the\n    desktop app uses this.\n  ",[223,7622,69,7623,69,7626,69,7657,16],{},[226,7624,7625],{},"Discovery file reading, endpoint validation, token-stamped requests.",[226,7627,7628,7631,7632,859,7634,859,7636,859,7639,859,7642,859,7645,859,7648,859,7651,2038,7654,231],{},[57,7629,7630],{},"createOpenPetsClient()"," factory returning ",[57,7633,858],{},[57,7635,862],{},[57,7637,7638],{},"listPets",[57,7640,7641],{},"installPet",[57,7643,7644],{},"acquireLease",[57,7646,7647],{},"heartbeatLease",[57,7649,7650],{},"releaseLease",[57,7652,7653],{},"react",[57,7655,7656],{},"say",[226,7658,7659,7660,7663],{},"Strongly typed protocol, custom ",[57,7661,7662],{},"OpenPetsClientError"," with stable error codes.",[65,7665,69,7667,69,7674,16],{"className":7666},[485],[65,7668,7670,7672],{"className":7669},[489],[491,7671,386],{},[491,7673,1306],{},[498,7675,7676],{},[57,7677,7678],{},"npm install @open-pets/client",[11,7680,16,7683,16,7688,16,7694],{"id":7681,"className":7682},"cli",[15],[18,7684,7686],{"id":7685},"open-petscli",[57,7687,2340],{},[22,7689,7690,7691,7693],{},"\n    The published npm CLI package. See\n    ",[41,7692,165],{"to":164}," for every command.\n  ",[65,7695,69,7697,69,7704,16],{"className":7696},[485],[65,7698,7700,7702],{"className":7699},[489],[491,7701,386],{},[491,7703,1306],{},[498,7705,7706],{},[57,7707,7708],{},"npx -y @open-pets/cli@latest configure --agent claude\n# optional permanent shell command:\nnpm install -g @open-pets/cli",[11,7710,16,7712,16,7717,16,7722],{"id":6401,"className":7711},[15],[18,7713,7715],{"id":7714},"open-petsmcp",[57,7716,2702],{},[22,7718,7719,7720,378],{},"\n    The OpenPets MCP server. Stdio transport, three tools, lease-aware\n    lifecycle. See\n    ",[41,7721,154],{"to":43},[65,7723,69,7725,69,7733,16],{"className":7724},[485],[65,7726,7728,7731],{"className":7727},[489],[491,7729,7730],{},"Run",[491,7732,1306],{},[498,7734,7735],{},[57,7736,3021],{},[11,7738,16,7740,16,7745,16,7748],{"id":2517,"className":7739},[15],[18,7741,7743],{"id":7742},"open-petsclaude",[57,7744,7566],{},[22,7746,7747],{},"\n    Claude Code integration package. Contains the hook runtime, hook\n    settings manager, and MCP configuration helpers used by the desktop app\n    and the CLI.\n  ",[223,7749,69,7750,69,7756,69,7770,16],{},[226,7751,7752,7755],{},[57,7753,7754],{},"runClaudeHookFromStdin()"," — execute one Claude hook event.",[226,7757,7758,859,7761,859,7764,7767,7768,231],{},[57,7759,7760],{},"installClaudeHooks()",[57,7762,7763],{},"uninstallClaudeHooks()",[57,7765,7766],{},"doctorClaudeHooks()"," — manage ",[57,7769,2088],{},[226,7771,7772,859,7775,859,7778,7781],{},[57,7773,7774],{},"buildClaudeMcpPreview()",[57,7776,7777],{},"parseClaudeMcpGetOutput()",[57,7779,7780],{},"classifyClaudeMcpStatus()"," — inspect Claude MCP config.",[11,7783,16,7785,16,7790,16,7793],{"id":2121,"className":7784},[15],[18,7786,7788],{"id":7787},"open-petsopencode",[57,7789,7576],{},[22,7791,7792],{},"\n    OpenCode integration package. Ships the OpenPets OpenCode plugin and\n    the project/global config managers.\n  ",[223,7794,69,7795,69,7801,69,7810,16],{},[226,7796,7797,7800],{},[57,7798,7799],{},"plugin.ts"," — default export consumed by OpenCode.",[226,7802,7803,6314,7806,7809],{},[57,7804,7805],{},"prepareOpenCodeProjectSetup()",[57,7807,7808],{},"writePreparedOpenCodeProjectSetup()"," — atomic project-level config writes.",[226,7811,7812,6314,7815,7818],{},[57,7813,7814],{},"prepareOpenCodeGlobalSetup()",[57,7816,7817],{},"writePreparedOpenCodeGlobalSetup()"," — global config writes used by the desktop app.",[11,7820,16,7823,16,7828,16,7831],{"id":7821,"className":7822},"agent-events",[15],[18,7824,7826],{"id":7825},"open-petsagent-events",[57,7827,7586],{},[22,7829,7830],{},"\n    Shared speech pools and validator. Both the Claude hook runtime and the\n    OpenCode plugin use this so the messages they emit feel consistent and\n    pass the same safety rules.\n  ",[223,7832,69,7833,69,7848,69,7854,16],{},[226,7834,7835,7838,7839,859,7841,859,7843,859,7845,2438],{},[57,7836,7837],{},"hookSpeechPools"," — readonly record keyed by category (",[57,7840,1090],{},[57,7842,1160],{},[57,7844,1170],{},[57,7846,7847],{},"permission",[226,7849,7850,7853],{},[57,7851,7852],{},"pickHookSpeech(category, randomFn)"," — pick one message safely.",[226,7855,7856,7859],{},[57,7857,7858],{},"validateHookSpeech(message)"," — reject unsafe-looking content.",[11,7861,16,7863,16,7867,16,7870,16,7885],{"id":1766,"className":7862},[15],[18,7864,7865],{"id":1766},[57,7866,1766],{},[22,7868,7869],{},"\n    Standalone CLI to install a single pet. Tries the running desktop app\n    first; falls back to a direct download if the app is unavailable.\n  ",[65,7871,69,7873,69,7881,16],{"className":7872},[485],[65,7874,7876,7879],{"className":7875},[489],[491,7877,7878],{},"Install one pet",[491,7880,1306],{},[498,7882,7883],{},[57,7884,1782],{},[22,7886,7887],{},"\n    Useful in dotfiles, CI bootstraps, and anywhere you cannot assume the\n    OpenPets desktop app is open.\n  ",[11,7889,16,7892,16,7897,16,7900],{"id":7890,"className":7891},"pet-format",[15],[18,7893,7895],{"id":7894},"open-petspet-format",[57,7896,7605],{},[22,7898,7899],{},"\n    Tiny marker package exporting a nominal type and a constant for\n    packages that conform to the OpenPets pet format. Use it when you build\n    tooling on top of OpenPets and want to identify pet packages at the\n    type level.\n  ",[22,7901,7902,7903,378],{},"\n    The actual pet-package schema lives in the desktop app's catalog\n    validator and the Codex pet validator — see\n    ",[41,7904,176],{"to":175},{"title":244,"searchDepth":245,"depth":245,"links":7906},[7907,7908,7909,7910,7911,7912,7913,7914,7915],{"id":1997,"depth":245,"text":2001},{"id":7615,"depth":245,"text":7535},{"id":7685,"depth":245,"text":2340},{"id":7714,"depth":245,"text":2702},{"id":7742,"depth":245,"text":7566},{"id":7787,"depth":245,"text":7576},{"id":7825,"depth":245,"text":7586},{"id":1766,"depth":245,"text":1766},{"id":7894,"depth":245,"text":7605},"Every @open-pets/* npm package — what it does, what to install, and when to depend on it.",{},"Packages",140,{"title":7470,"description":7916},"docs/packages",[7923,7924,7925,7926,7927,7928,7929,7930,7931],{"id":1997,"label":2001},{"id":7611,"label":7535},{"id":7681,"label":2340},{"id":6401,"label":2702},{"id":2517,"label":7566},{"id":2121,"label":7576},{"id":7821,"label":7586},{"id":1766,"label":1766},{"id":7890,"label":7605},"dhwO8b_QO7g7M75PUSzwTZTKEsscXo7MFiR7NnPdapY",{"id":7934,"title":7935,"body":7936,"description":8067,"extension":251,"meta":8068,"navTitle":8069,"navigation":253,"order":8070,"path":8071,"seo":8072,"stem":8073,"toc":8074,"__hash__":8078},"docs_en/docs/license.md","License & attribution",{"type":8,"value":7937,"toc":8062},[7938,7983,7997],[11,7939,16,7942,16,7945,16,7953],{"id":7940,"className":7941},"code-license",[15],[18,7943,7944],{"id":7940},"Code license",[22,7946,7947,7948,7952],{},"\n    OpenPets source code is released under the\n    ",[374,7949,7951],{"href":7950},"https://github.com/alvinunreal/openpets/blob/main/LICENSE","MIT License",".\n    The license applies to the desktop application, every workspace\n    package, and the website source.\n  ",[65,7954,69,7956,69,7964,16],{"className":7955},[485],[65,7957,7959,7962],{"className":7958},[489],[491,7960,7961],{},"LICENSE",[491,7963,496],{},[498,7965,7966,7978],{},[57,7967,7968,7969,7972,7975],{},"MIT License\n",[22,7970,7971],{},"Copyright (c) 2026 OpenPets",[22,7973,7974],{},"Permission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:",[22,7976,7977],{},"The above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.",[22,7979,7980],{},[57,7981,7982],{},"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND...",[11,7984,16,7986,16,7988,16,7991],{"id":961,"className":7985},[15],[18,7987,965],{"id":961},[22,7989,7990],{},"\n    Pet spritesheets and preview images are not covered by the OpenPets\n    code license. Each pet ships with its own metadata; pet creators retain\n    the rights to their artwork unless they explicitly relicense it.\n  ",[22,7992,7993,7994,7996],{},"\n    If you want to redistribute or remix a specific pet, check the\n    licensing notes on that pet's gallery entry or its\n    ",[57,7995,1841],{}," metadata before doing so.\n  ",[11,7998,16,8001,16,8005,16,8008,16,8059],{"id":7999,"className":8000},"third-party",[15],[18,8002,8004],{"id":8003},"third-party-software","Third-party software",[22,8006,8007],{},"\n    OpenPets stands on a number of excellent open-source projects. Major\n    runtime dependencies include:\n  ",[223,8009,69,8010,69,8017,69,8024,69,8031,69,8038,69,8045,69,8052,16],{},[226,8011,8012,8016],{},[374,8013,8015],{"href":8014},"https://www.electronjs.org/","Electron"," — desktop app shell.",[226,8018,8019,8023],{},[374,8020,8022],{"href":8021},"https://github.com/modelcontextprotocol/typescript-sdk","@modelcontextprotocol/sdk"," — MCP server implementation.",[226,8025,8026,8030],{},[374,8027,8029],{"href":8028},"https://github.com/thejoshwolfe/yauzl","yauzl"," — streaming ZIP extraction for pet packages.",[226,8032,8033,8037],{},[374,8034,8036],{"href":8035},"https://github.com/microsoft/node-jsonc-parser","jsonc-parser"," — JSONC-aware OpenCode config edits.",[226,8039,8040,8044],{},[374,8041,8043],{"href":8042},"https://zod.dev/","zod"," — runtime schema validation in the MCP server.",[226,8046,8047,8051],{},[374,8048,8050],{"href":8049},"https://highlightjs.org/","highlight.js"," — code highlighting on this documentation site.",[226,8053,8054,8058],{},[374,8055,8057],{"href":8056},"https://nuxt.com/","Nuxt"," — the framework powering openpets.dev.",[22,8060,8061],{},"\n    Each dependency is governed by its own license. See the source code in\n    the OpenPets GitHub repository for the full list and the corresponding\n    license texts.\n  ",{"title":244,"searchDepth":245,"depth":245,"links":8063},[8064,8065,8066],{"id":7940,"depth":245,"text":7944},{"id":961,"depth":245,"text":965},{"id":8003,"depth":245,"text":8004},"OpenPets licensing terms — MIT for code, per-pet for assets — and third-party attribution.",{},"License",150,"/docs/license",{"title":7935,"description":8067},"docs/license",[8075,8076,8077],{"id":7940,"label":7944},{"id":961,"label":965},{"id":7999,"label":8004},"Hiz8jzCmRfHIBxyksOBOGA_NFjdx292gZH13emtHfmM",1781349630632]