[{"data":1,"prerenderedAt":1232},["ShallowReactive",2],{"guides-list":3},[4,655,860],{"id":5,"title":6,"body":7,"category":646,"description":647,"extension":648,"meta":649,"navigation":168,"order":129,"path":650,"readingTime":651,"seo":652,"stem":653,"__hash__":654},"guides/guides/building-an-ai-monitoring-app.md","Building an AI monitoring app",{"type":8,"value":9,"toc":637},"minimal",[10,14,18,23,57,61,78,81,101,112,116,483,490,494,540,544,592,595,599,606,610,630,633],[11,12,6],"h1",{"id":13},"building-an-ai-monitoring-app",[15,16,17],"p",{},"This guide walks you through the shape of an AI-verification app on CHeKT: a third-party service that listens to alarm events, fetches snapshots, runs them through a vision model, and writes back a verdict.",[19,20,22],"h2",{"id":21},"the-shape-of-the-integration","The shape of the integration",[24,25,26,39,45,51],"ul",{},[27,28,29,33,34],"li",{},[30,31,32],"strong",{},"Pattern:"," ",[35,36,38],"a",{"href":37},"/apps","CHeKT Apps",[27,40,41,44],{},[30,42,43],{},"Auth:"," API key",[27,46,47,50],{},[30,48,49],{},"Direction:"," AI app → CHeKT (your service calls our API)",[27,52,53,56],{},[30,54,55],{},"Time to first response:"," 45 minutes for a working prototype.",[19,58,60],{"id":59},"_1-create-the-app","1. Create the app",[15,62,63,64,68,69,68,72,68,74,77],{},"Sign in to ",[65,66,67],"code",{},"dealer.chekt.com"," → ",[30,70,71],{},"Settings",[30,73,38],{},[30,75,76],{},"New app",".",[15,79,80],{},"Permissions you need:",[24,82,83,89,95],{},[27,84,85,88],{},[65,86,87],{},"events:read"," — to confirm alarm context",[27,90,91,94],{},[65,92,93],{},"snapshots:read"," — to fetch images for analysis",[27,96,97,100],{},[65,98,99],{},"alarms:write"," — to acknowledge or annotate",[15,102,103,104,107,108,111],{},"Subscribe to the ",[65,105,106],{},"alarm.created"," and ",[65,109,110],{},"snapshot.created"," events.",[19,113,115],{"id":114},"_2-stand-up-a-webhook-receiver","2. Stand up a webhook receiver",[117,118,123],"pre",{"className":119,"code":120,"language":121,"meta":122,"style":122},"language-ts shiki shiki-themes github-light github-dark","import express from \"express\";\nimport crypto from \"crypto\";\n\nconst app = express();\napp.use(express.json({ verify: (req, _res, buf) => (req.rawBody = buf) }));\n\napp.post(\"/webhooks/chekt\", (req, res) => {\n  const sig = req.headers[\"x-chekt-signature\"] as string;\n  const expected = crypto\n    .createHmac(\"sha256\", process.env.CHEKT_WEBHOOK_SECRET!)\n    .update(req.rawBody)\n    .digest(\"hex\");\n\n  if (sig !== expected) return res.status(401).end();\n\n  if (req.body.type === \"alarm.created\") {\n    queue.publish(\"analyze\", req.body.data);\n  }\n  res.sendStatus(200);\n});\n","ts","",[65,124,125,148,163,170,190,244,249,280,308,321,347,358,374,379,416,421,438,455,461,477],{"__ignoreMap":122},[126,127,130,134,138,141,145],"span",{"class":128,"line":129},"line",1,[126,131,133],{"class":132},"szBVR","import",[126,135,137],{"class":136},"sVt8B"," express ",[126,139,140],{"class":132},"from",[126,142,144],{"class":143},"sZZnC"," \"express\"",[126,146,147],{"class":136},";\n",[126,149,151,153,156,158,161],{"class":128,"line":150},2,[126,152,133],{"class":132},[126,154,155],{"class":136}," crypto ",[126,157,140],{"class":132},[126,159,160],{"class":143}," \"crypto\"",[126,162,147],{"class":136},[126,164,166],{"class":128,"line":165},3,[126,167,169],{"emptyLinePlaceholder":168},true,"\n",[126,171,173,176,180,183,187],{"class":128,"line":172},4,[126,174,175],{"class":132},"const",[126,177,179],{"class":178},"sj4cs"," app",[126,181,182],{"class":132}," =",[126,184,186],{"class":185},"sScJk"," express",[126,188,189],{"class":136},"();\n",[126,191,193,196,199,202,205,208,211,214,218,221,224,226,229,232,235,238,241],{"class":128,"line":192},5,[126,194,195],{"class":136},"app.",[126,197,198],{"class":185},"use",[126,200,201],{"class":136},"(express.",[126,203,204],{"class":185},"json",[126,206,207],{"class":136},"({ ",[126,209,210],{"class":185},"verify",[126,212,213],{"class":136},": (",[126,215,217],{"class":216},"s4XuR","req",[126,219,220],{"class":136},", ",[126,222,223],{"class":216},"_res",[126,225,220],{"class":136},[126,227,228],{"class":216},"buf",[126,230,231],{"class":136},") ",[126,233,234],{"class":132},"=>",[126,236,237],{"class":136}," (req.rawBody ",[126,239,240],{"class":132},"=",[126,242,243],{"class":136}," buf) }));\n",[126,245,247],{"class":128,"line":246},6,[126,248,169],{"emptyLinePlaceholder":168},[126,250,252,254,257,260,263,266,268,270,273,275,277],{"class":128,"line":251},7,[126,253,195],{"class":136},[126,255,256],{"class":185},"post",[126,258,259],{"class":136},"(",[126,261,262],{"class":143},"\"/webhooks/chekt\"",[126,264,265],{"class":136},", (",[126,267,217],{"class":216},[126,269,220],{"class":136},[126,271,272],{"class":216},"res",[126,274,231],{"class":136},[126,276,234],{"class":132},[126,278,279],{"class":136}," {\n",[126,281,283,286,289,291,294,297,300,303,306],{"class":128,"line":282},8,[126,284,285],{"class":132},"  const",[126,287,288],{"class":178}," sig",[126,290,182],{"class":132},[126,292,293],{"class":136}," req.headers[",[126,295,296],{"class":143},"\"x-chekt-signature\"",[126,298,299],{"class":136},"] ",[126,301,302],{"class":132},"as",[126,304,305],{"class":178}," string",[126,307,147],{"class":136},[126,309,311,313,316,318],{"class":128,"line":310},9,[126,312,285],{"class":132},[126,314,315],{"class":178}," expected",[126,317,182],{"class":132},[126,319,320],{"class":136}," crypto\n",[126,322,324,327,330,332,335,338,341,344],{"class":128,"line":323},10,[126,325,326],{"class":136},"    .",[126,328,329],{"class":185},"createHmac",[126,331,259],{"class":136},[126,333,334],{"class":143},"\"sha256\"",[126,336,337],{"class":136},", process.env.",[126,339,340],{"class":178},"CHEKT_WEBHOOK_SECRET",[126,342,343],{"class":132},"!",[126,345,346],{"class":136},")\n",[126,348,350,352,355],{"class":128,"line":349},11,[126,351,326],{"class":136},[126,353,354],{"class":185},"update",[126,356,357],{"class":136},"(req.rawBody)\n",[126,359,361,363,366,368,371],{"class":128,"line":360},12,[126,362,326],{"class":136},[126,364,365],{"class":185},"digest",[126,367,259],{"class":136},[126,369,370],{"class":143},"\"hex\"",[126,372,373],{"class":136},");\n",[126,375,377],{"class":128,"line":376},13,[126,378,169],{"emptyLinePlaceholder":168},[126,380,382,385,388,391,394,397,400,403,405,408,411,414],{"class":128,"line":381},14,[126,383,384],{"class":132},"  if",[126,386,387],{"class":136}," (sig ",[126,389,390],{"class":132},"!==",[126,392,393],{"class":136}," expected) ",[126,395,396],{"class":132},"return",[126,398,399],{"class":136}," res.",[126,401,402],{"class":185},"status",[126,404,259],{"class":136},[126,406,407],{"class":178},"401",[126,409,410],{"class":136},").",[126,412,413],{"class":185},"end",[126,415,189],{"class":136},[126,417,419],{"class":128,"line":418},15,[126,420,169],{"emptyLinePlaceholder":168},[126,422,424,426,429,432,435],{"class":128,"line":423},16,[126,425,384],{"class":132},[126,427,428],{"class":136}," (req.body.type ",[126,430,431],{"class":132},"===",[126,433,434],{"class":143}," \"alarm.created\"",[126,436,437],{"class":136},") {\n",[126,439,441,444,447,449,452],{"class":128,"line":440},17,[126,442,443],{"class":136},"    queue.",[126,445,446],{"class":185},"publish",[126,448,259],{"class":136},[126,450,451],{"class":143},"\"analyze\"",[126,453,454],{"class":136},", req.body.data);\n",[126,456,458],{"class":128,"line":457},18,[126,459,460],{"class":136},"  }\n",[126,462,464,467,470,472,475],{"class":128,"line":463},19,[126,465,466],{"class":136},"  res.",[126,468,469],{"class":185},"sendStatus",[126,471,259],{"class":136},[126,473,474],{"class":178},"200",[126,476,373],{"class":136},[126,478,480],{"class":128,"line":479},20,[126,481,482],{"class":136},"});\n",[15,484,485,486,489],{},"The 200 is the ",[30,487,488],{},"only"," thing CHeKT cares about. Do real work in a queue.",[19,491,493],{"id":492},"_3-fetch-the-snapshot","3. Fetch the snapshot",[117,495,497],{"className":119,"code":496,"language":121,"meta":122,"style":122},"const snap = await chekt.snapshots.get(alarm.snapshot_id);\nconst verdict = await vision.classify(snap.url);\n",[65,498,499,520],{"__ignoreMap":122},[126,500,501,503,506,508,511,514,517],{"class":128,"line":129},[126,502,175],{"class":132},[126,504,505],{"class":178}," snap",[126,507,182],{"class":132},[126,509,510],{"class":132}," await",[126,512,513],{"class":136}," chekt.snapshots.",[126,515,516],{"class":185},"get",[126,518,519],{"class":136},"(alarm.snapshot_id);\n",[126,521,522,524,527,529,531,534,537],{"class":128,"line":150},[126,523,175],{"class":132},[126,525,526],{"class":178}," verdict",[126,528,182],{"class":132},[126,530,510],{"class":132},[126,532,533],{"class":136}," vision.",[126,535,536],{"class":185},"classify",[126,538,539],{"class":136},"(snap.url);\n",[19,541,543],{"id":542},"_4-write-the-verdict-back","4. Write the verdict back",[117,545,547],{"className":119,"code":546,"language":121,"meta":122,"style":122},"await chekt.alarms.annotate(alarm.id, {\n  source: \"ai-verifier\",\n  verdict: verdict.label,        // \"intruder\" | \"false-positive\" | \"uncertain\"\n  confidence: verdict.confidence,\n});\n",[65,548,549,563,574,583,588],{"__ignoreMap":122},[126,550,551,554,557,560],{"class":128,"line":129},[126,552,553],{"class":132},"await",[126,555,556],{"class":136}," chekt.alarms.",[126,558,559],{"class":185},"annotate",[126,561,562],{"class":136},"(alarm.id, {\n",[126,564,565,568,571],{"class":128,"line":150},[126,566,567],{"class":136},"  source: ",[126,569,570],{"class":143},"\"ai-verifier\"",[126,572,573],{"class":136},",\n",[126,575,576,579],{"class":128,"line":165},[126,577,578],{"class":136},"  verdict: verdict.label,        ",[126,580,582],{"class":581},"sJ8bj","// \"intruder\" | \"false-positive\" | \"uncertain\"\n",[126,584,585],{"class":128,"line":172},[126,586,587],{"class":136},"  confidence: verdict.confidence,\n",[126,589,590],{"class":128,"line":192},[126,591,482],{"class":136},[15,593,594],{},"A central station operator now sees the AI annotation alongside the alarm in real time.",[19,596,598],{"id":597},"_5-handle-retries-safely","5. Handle retries safely",[15,600,601,602,77],{},"Use idempotency keys on every write. CHeKT retries webhooks with exponential backoff for 24 hours — your side might receive duplicates. See ",[35,603,605],{"href":604},"/docs/idempotency","Idempotency",[19,607,609],{"id":608},"what-to-ship-next","What to ship next",[24,611,612,618,624],{},[27,613,614,617],{},[30,615,616],{},"Acknowledge low-confidence false positives"," — reduce operator load.",[27,619,620,623],{},[30,621,622],{},"Dispatch on high-confidence intruder events"," — auto-escalate.",[27,625,626,629],{},[30,627,628],{},"Surface metrics in your dashboard"," — AI catch rate, false-positive rate.",[15,631,632],{},"That's it — a real AI integration in a single afternoon.",[634,635,636],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":122,"searchDepth":165,"depth":165,"links":638},[639,640,641,642,643,644,645],{"id":21,"depth":150,"text":22},{"id":59,"depth":150,"text":60},{"id":114,"depth":150,"text":115},{"id":492,"depth":150,"text":493},{"id":542,"depth":150,"text":543},{"id":597,"depth":150,"text":598},{"id":608,"depth":150,"text":609},"Integration","How to ship a Public-API-driven AI integration in a weekend.","md",{},"/guides/building-an-ai-monitoring-app","12 min",{"title":6,"description":647},"guides/building-an-ai-monitoring-app","_mkwX7ZZEYLv-_WCiqKj6BVCfmJARjLrBCjNBOHSYsM",{"id":656,"title":657,"body":658,"category":852,"description":853,"extension":648,"meta":854,"navigation":168,"order":150,"path":855,"readingTime":856,"seo":857,"stem":858,"__hash__":859},"guides/guides/migrating-platform-linking.md","Migrating from 2-way to Platform Linking",{"type":8,"value":659,"toc":841},[660,663,666,673,677,703,707,714,771,778,782,787,790,793,797,816,820,823,827,830,834],[11,661,657],{"id":662},"migrating-from-2-way-to-platform-linking",[15,664,665],{},"For years, CHeKT and its biggest partners ran two-way integrations. CHeKT called the partner's APIs; the partner called ours; both sides kept state in sync. It worked, until it didn't.",[15,667,668,669,672],{},"This guide explains why every integration today is ",[30,670,671],{},"external → CHeKT"," (Partner API + webhooks) and what the migration path looks like for older two-way integrations.",[19,674,676],{"id":675},"the-problem-with-two-way","The problem with two-way",[24,678,679,685,691,697],{},[27,680,681,684],{},[30,682,683],{},"Drift."," Two systems holding the same state always disagree at some point. Resolution is expensive.",[27,686,687,690],{},[30,688,689],{},"Coupling."," A change on either side breaks the other. Coordination kills speed.",[27,692,693,696],{},[30,694,695],{},"Auth complexity."," Two sets of keys, two webhooks, two retry policies, double the failure modes.",[27,698,699,702],{},[30,700,701],{},"Onboarding cost."," Every new partner becomes a custom project. The marginal cost never drops.",[19,704,706],{"id":705},"the-new-model","The new model",[15,708,709,710,713],{},"We split integrations into two patterns. Both flow in the same direction — ",[30,711,712],{},"into CHeKT"," — but hit different API surfaces:",[715,716,717,736],"table",{},[718,719,720],"thead",{},[721,722,723,727,730,733],"tr",{},[724,725,726],"th",{},"Pattern",[724,728,729],{},"Direction",[724,731,732],{},"API surface",[724,734,735],{},"Auth",[737,738,739,755],"tbody",{},[721,740,741,746,749,752],{},[742,743,744],"td",{},[30,745,38],{},[742,747,748],{},"Third-party → CHeKT",[742,750,751],{},"Public API",[742,753,754],{},"API Key",[721,756,757,762,765,768],{},[742,758,759],{},[30,760,761],{},"Platform Linking",[742,763,764],{},"Partner platform → CHeKT",[742,766,767],{},"Partner API",[742,769,770],{},"API Key → OAuth → Assertion Token",[15,772,773,774,777],{},"If you find yourself building outbound calls ",[775,776,140],"em",{}," CHeKT into your platform, stop. CHeKT exposes events over webhooks and data over the Partner API — your side consumes both.",[19,779,781],{"id":780},"migration-steps-for-existing-two-way-partners","Migration steps for existing two-way partners",[783,784,786],"h3",{"id":785},"step-1-confirm-chekt-is-the-source-of-truth-for-operational-data","Step 1 — Confirm CHeKT is the source of truth for operational data",[15,788,789],{},"Events, alarms, dispatches, and audit logs live in CHeKT. Drop any code on your side that pushes those into CHeKT — it's no longer needed.",[15,791,792],{},"Anything your platform owns (video, panel configuration, your own UI state) stays on your side. CHeKT will not call out to fetch it.",[783,794,796],{"id":795},"step-2-pick-the-right-auth-tier","Step 2 — Pick the right auth tier",[24,798,799,804,810],{},[27,800,801,803],{},[30,802,754],{}," — stable, server-to-server, low ceremony. Best starting point.",[27,805,806,809],{},[30,807,808],{},"OAuth 2.0"," — user-mediated grants on your platform's users. Use when the integration is per-user, not per-platform.",[27,811,812,815],{},[30,813,814],{},"Assertion Tokens"," — signed JWTs with rotating keys. Strictest trust tier; reserve for high-volume, high-stakes service-to-service.",[783,817,819],{"id":818},"step-3-subscribe-to-webhooks-instead-of-polling","Step 3 — Subscribe to webhooks instead of polling",[15,821,822],{},"Anywhere your old code polled CHeKT on a timer, replace it with a webhook subscription. Less load, lower latency, fewer surprises during traffic spikes.",[783,824,826],{"id":825},"step-4-retire-chekts-old-outbound-endpoints-into-your-service","Step 4 — Retire CHeKT's old outbound endpoints into your service",[15,828,829],{},"Once your side is calling the Partner API for enrichment and consuming events via webhooks, the legacy outbound path from CHeKT into your platform can be decommissioned. Less code is less to break.",[19,831,833],{"id":832},"what-we-learned","What we learned",[15,835,836,837,840],{},"The biggest lesson: ",[30,838,839],{},"direction matters more than features",". A clean one-direction integration with fewer features ships faster, breaks less, and onboards new partners in days, not quarters.",{"title":122,"searchDepth":165,"depth":165,"links":842},[843,844,845,851],{"id":675,"depth":150,"text":676},{"id":705,"depth":150,"text":706},{"id":780,"depth":150,"text":781,"children":846},[847,848,849,850],{"id":785,"depth":165,"text":786},{"id":795,"depth":165,"text":796},{"id":818,"depth":165,"text":819},{"id":825,"depth":165,"text":826},{"id":832,"depth":150,"text":833},"Architecture","Why we stopped doing bidirectional integrations and how to move to one-direction Platform Linking.",{},"/guides/migrating-platform-linking","8 min",{"title":657,"description":853},"guides/migrating-platform-linking","JUQg9DURbmsXiTh4ceyynDa0Ipp_K2zqB8ERb7d4LVQ",{"id":861,"title":862,"body":863,"category":1224,"description":1225,"extension":648,"meta":1226,"navigation":168,"order":165,"path":1227,"readingTime":1228,"seo":1229,"stem":1230,"__hash__":1231},"guides/guides/using-the-operator-cli.md","Using the Operator CLI in production",{"type":8,"value":864,"toc":1215},[865,868,875,879,923,927,986,993,997,1000,1049,1056,1060,1087,1090,1094,1117,1120,1124,1127,1151,1155,1205,1212],[11,866,862],{"id":867},"using-the-operator-cli-in-production",[15,869,870,871,874],{},"The Monitoring Portal is great. The terminal is faster. This guide walks through the real workflows operators use ",[65,872,873],{},"opcli"," for once they've been on it for a week.",[19,876,878],{"id":877},"install-once","Install once",[117,880,884],{"className":881,"code":882,"language":883,"meta":122,"style":122},"language-bash shiki shiki-themes github-light github-dark","brew install chekt/tap/opcli\nopcli login                # opens browser; OAuth\nopcli config set tenant my-monitoring-co\n","bash",[65,885,886,897,907],{"__ignoreMap":122},[126,887,888,891,894],{"class":128,"line":129},[126,889,890],{"class":185},"brew",[126,892,893],{"class":143}," install",[126,895,896],{"class":143}," chekt/tap/opcli\n",[126,898,899,901,904],{"class":128,"line":150},[126,900,873],{"class":185},[126,902,903],{"class":143}," login",[126,905,906],{"class":581},"                # opens browser; OAuth\n",[126,908,909,911,914,917,920],{"class":128,"line":165},[126,910,873],{"class":185},[126,912,913],{"class":143}," config",[126,915,916],{"class":143}," set",[126,918,919],{"class":143}," tenant",[126,921,922],{"class":143}," my-monitoring-co\n",[19,924,926],{"id":925},"the-morning-routine","The morning routine",[117,928,930],{"className":881,"code":929,"language":883,"meta":122,"style":122},"opcli alarms --active --priority high   # what's open right now\nopcli incidents --since \"1h\" --json | jq '.[] | .id'\nopcli health                            # device status across all sites\n",[65,931,932,951,976],{"__ignoreMap":122},[126,933,934,936,939,942,945,948],{"class":128,"line":129},[126,935,873],{"class":185},[126,937,938],{"class":143}," alarms",[126,940,941],{"class":178}," --active",[126,943,944],{"class":178}," --priority",[126,946,947],{"class":143}," high",[126,949,950],{"class":581},"   # what's open right now\n",[126,952,953,955,958,961,964,967,970,973],{"class":128,"line":150},[126,954,873],{"class":185},[126,956,957],{"class":143}," incidents",[126,959,960],{"class":178}," --since",[126,962,963],{"class":143}," \"1h\"",[126,965,966],{"class":178}," --json",[126,968,969],{"class":132}," |",[126,971,972],{"class":185}," jq",[126,974,975],{"class":143}," '.[] | .id'\n",[126,977,978,980,983],{"class":128,"line":165},[126,979,873],{"class":185},[126,981,982],{"class":143}," health",[126,984,985],{"class":581},"                            # device status across all sites\n",[15,987,988,989,992],{},"Most operators alias these into ",[65,990,991],{},"morning"," and run it at start-of-shift.",[19,994,996],{"id":995},"acknowledging-in-batches","Acknowledging in batches",[15,998,999],{},"When a sensor goes haywire and floods, you can ACK the batch in one shot:",[117,1001,1003],{"className":881,"code":1002,"language":883,"meta":122,"style":122},"opcli alarms --device dev_8h2j3kfm --status new \\\n  | opcli alarm acknowledge --stdin --reason \"false-positive: sensor recalibration\"\n",[65,1004,1005,1026],{"__ignoreMap":122},[126,1006,1007,1009,1011,1014,1017,1020,1023],{"class":128,"line":129},[126,1008,873],{"class":185},[126,1010,938],{"class":143},[126,1012,1013],{"class":178}," --device",[126,1015,1016],{"class":143}," dev_8h2j3kfm",[126,1018,1019],{"class":178}," --status",[126,1021,1022],{"class":143}," new",[126,1024,1025],{"class":178}," \\\n",[126,1027,1028,1031,1034,1037,1040,1043,1046],{"class":128,"line":150},[126,1029,1030],{"class":132},"  |",[126,1032,1033],{"class":185}," opcli",[126,1035,1036],{"class":143}," alarm",[126,1038,1039],{"class":143}," acknowledge",[126,1041,1042],{"class":178}," --stdin",[126,1044,1045],{"class":178}," --reason",[126,1047,1048],{"class":143}," \"false-positive: sensor recalibration\"\n",[15,1050,1051,1052,1055],{},"The CLI is ",[30,1053,1054],{},"pipe-friendly by design",". JSON in, JSON out.",[19,1057,1059],{"id":1058},"dispatch","Dispatch",[117,1061,1063],{"className":881,"code":1062,"language":883,"meta":122,"style":122},"opcli dispatch guard --to \"Main Entrance\" --from-alarm A-10293\n",[65,1064,1065],{"__ignoreMap":122},[126,1066,1067,1069,1072,1075,1078,1081,1084],{"class":128,"line":129},[126,1068,873],{"class":185},[126,1070,1071],{"class":143}," dispatch",[126,1073,1074],{"class":143}," guard",[126,1076,1077],{"class":178}," --to",[126,1079,1080],{"class":143}," \"Main Entrance\"",[126,1082,1083],{"class":178}," --from-alarm",[126,1085,1086],{"class":143}," A-10293\n",[15,1088,1089],{},"CHeKT routes the dispatch to the nearest available guard service tied to that site. The CLI returns the dispatch ID, ETA, and a live tracking URL.",[19,1091,1093],{"id":1092},"live-camera","Live camera",[117,1095,1097],{"className":881,"code":1096,"language":883,"meta":122,"style":122},"opcli camera \"Main Entrance\" --live --layout grid\n",[65,1098,1099],{"__ignoreMap":122},[126,1100,1101,1103,1106,1108,1111,1114],{"class":128,"line":129},[126,1102,873],{"class":185},[126,1104,1105],{"class":143}," camera",[126,1107,1080],{"class":143},[126,1109,1110],{"class":178}," --live",[126,1112,1113],{"class":178}," --layout",[126,1115,1116],{"class":143}," grid\n",[15,1118,1119],{},"This opens an mpv window with the live feed. On macOS, you can pipe it into QuickLook.",[19,1121,1123],{"id":1122},"audit-ready-logs","Audit-ready logs",[15,1125,1126],{},"Every command is logged with timestamp, operator, target, and result. Pull the audit log straight from the CLI:",[117,1128,1130],{"className":881,"code":1129,"language":883,"meta":122,"style":122},"opcli audit --operator $USER --since 24h\n",[65,1131,1132],{"__ignoreMap":122},[126,1133,1134,1136,1139,1142,1145,1148],{"class":128,"line":129},[126,1135,873],{"class":185},[126,1137,1138],{"class":143}," audit",[126,1140,1141],{"class":178}," --operator",[126,1143,1144],{"class":136}," $USER ",[126,1146,1147],{"class":178},"--since",[126,1149,1150],{"class":143}," 24h\n",[19,1152,1154],{"id":1153},"when-to-use-the-cli-vs-the-portal","When to use the CLI vs the Portal",[715,1156,1157,1167],{},[718,1158,1159],{},[721,1160,1161,1164],{},[724,1162,1163],{},"Workflow",[724,1165,1166],{},"Use this",[737,1168,1169,1177,1185,1193],{},[721,1170,1171,1174],{},[742,1172,1173],{},"First-time triage",[742,1175,1176],{},"Portal — visual context.",[721,1178,1179,1182],{},[742,1180,1181],{},"Bulk acknowledgement",[742,1183,1184],{},"CLI — one pipe.",[721,1186,1187,1190],{},[742,1188,1189],{},"Automated dispatches",[742,1191,1192],{},"CLI from a queue worker.",[721,1194,1195,1198],{},[742,1196,1197],{},"Compliance audits",[742,1199,1200,1201,1204],{},"CLI — ",[65,1202,1203],{},"--json"," is grep-able.",[15,1206,1207,1208,1211],{},"The CLI is not a replacement for the Portal. It's the ",[30,1209,1210],{},"second tool"," every operator picks up after they've outgrown clicking.",[634,1213,1214],{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":122,"searchDepth":165,"depth":165,"links":1216},[1217,1218,1219,1220,1221,1222,1223],{"id":877,"depth":150,"text":878},{"id":925,"depth":150,"text":926},{"id":995,"depth":150,"text":996},{"id":1058,"depth":150,"text":1059},{"id":1092,"depth":150,"text":1093},{"id":1122,"depth":150,"text":1123},{"id":1153,"depth":150,"text":1154},"Operators","Real workflows central station operators run from the terminal.",{},"/guides/using-the-operator-cli","10 min",{"title":862,"description":1225},"guides/using-the-operator-cli","lbeKGiJWcntludypSFfEsR3LB4_quqYWTHCLFk2NrbQ",1779905486024]