[{"data":1,"prerenderedAt":667},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fguides\u002Fautomate":3},{"id":4,"title":5,"body":6,"description":660,"extension":661,"meta":662,"navigation":369,"path":663,"seo":664,"stem":665,"__hash__":666},"docs\u002Fdocs\u002Fguides\u002Fautomate.md","Put Slo on autopilot",{"type":7,"value":8,"toc":653},"minimark",[9,13,17,22,25,37,72,78,96,105,109,127,264,275,282,286,297,386,389,407,417,425,429,432,533,544,548,554,623,626,649],[10,11,5],"h1",{"id":12},"put-slo-on-autopilot",[14,15,16],"p",{},"Everything you do in the TUI, Slo can do without it. This guide covers three setups, from simplest to most involved: a review in CI, a morning report, and a scheduled check-in on a long-running workflow.",[18,19,21],"h2",{"id":20},"before-you-start","Before you start",[14,23,24],{},"Unattended runs don't see your shell profile or the sign-in you did in the TUI unless you set them up. Two things to sort out first:",[14,26,27,31,32,36],{},[28,29,30],"strong",{},"Credentials."," On your own machine, the saved sign-in from ",[33,34,35],"code",{},"\u002Fauth"," works. On a CI runner, use an API key from your secrets:",[38,39,44],"pre",{"className":40,"code":41,"language":42,"meta":43,"style":43},"language-bash shiki shiki-themes github-dark-high-contrast","export OPENAI_API_KEY=\"$CI_OPENAI_API_KEY\"\n","bash","",[33,45,46],{"__ignoreMap":43},[47,48,51,55,59,62,66,69],"span",{"class":49,"line":50},"line",1,[47,52,54],{"class":53},"sWyjQ","export",[47,56,58],{"class":57},"sMAXC"," OPENAI_API_KEY",[47,60,61],{"class":53},"=",[47,63,65],{"class":64},"sTRMh","\"",[47,67,68],{"class":57},"$CI_OPENAI_API_KEY",[47,70,71],{"class":64},"\"\n",[14,73,74,77],{},[28,75,76],{},"Pop-ups."," Turn off the visualizer window, since there's no screen to show it on:",[38,79,81],{"className":40,"code":80,"language":42,"meta":43,"style":43},"export SLO_AUTO_VISUALIZE=0\n",[33,82,83],{"__ignoreMap":43},[47,84,85,87,90,92],{"class":49,"line":50},[47,86,54],{"class":53},[47,88,89],{"class":57}," SLO_AUTO_VISUALIZE",[47,91,61],{"class":53},[47,93,95],{"class":94},"sCcAr","0\n",[14,97,98,99,104],{},"The ",[100,101,103],"a",{"href":102},"\u002Fdocs\u002Freference\u002Fenvironment-variables#ready-made-profiles","CI profile"," has a complete set.",[18,106,108],{"id":107},"_1-a-review-on-every-merge-request","1. A review on every merge request",[14,110,111,114,115,118,119,122,123,126],{},[33,112,113],{},"slo run"," prints one JSON event per line and exits with ",[33,116,117],{},"0",", ",[33,120,121],{},"1"," or ",[33,124,125],{},"2",". That's all a CI job needs.",[38,128,132],{"className":129,"code":130,"language":131,"meta":43,"style":43},"language-yaml shiki shiki-themes github-dark-high-contrast","# .gitlab-ci.yml\nslo-review:\n  stage: test\n  script:\n    - curl -fsSL https:\u002F\u002Fget-slo.sh\u002Finstall.sh | bash\n    - export PATH=\"$HOME\u002F.local\u002Fbin:$PATH\"\n    - |\n      slo run \\\n        -p \"Review the changes on this branch against main. Focus on bugs,\n            missing tests and anything that breaks our conventions in SLO.md.\n            End with BLOCKING or OK on its own line.\" \\\n        > review.jsonl\n    - jq -r 'select(.kind == \"run_completed\") | .content' review.jsonl | tee review.md\n    - tail -n 1 review.md | grep -q '^OK$'\n  artifacts:\n    paths: [review.md]\n","yaml",[33,133,134,140,150,162,170,179,187,195,201,207,213,219,225,233,241,249],{"__ignoreMap":43},[47,135,136],{"class":49,"line":50},[47,137,139],{"class":138},"sQrFR","# .gitlab-ci.yml\n",[47,141,143,147],{"class":49,"line":142},2,[47,144,146],{"class":145},"sKpQp","slo-review",[47,148,149],{"class":57},":\n",[47,151,153,156,159],{"class":49,"line":152},3,[47,154,155],{"class":145},"  stage",[47,157,158],{"class":57},": ",[47,160,161],{"class":64},"test\n",[47,163,165,168],{"class":49,"line":164},4,[47,166,167],{"class":145},"  script",[47,169,149],{"class":57},[47,171,173,176],{"class":49,"line":172},5,[47,174,175],{"class":57},"    - ",[47,177,178],{"class":64},"curl -fsSL https:\u002F\u002Fget-slo.sh\u002Finstall.sh | bash\n",[47,180,182,184],{"class":49,"line":181},6,[47,183,175],{"class":57},[47,185,186],{"class":64},"export PATH=\"$HOME\u002F.local\u002Fbin:$PATH\"\n",[47,188,190,192],{"class":49,"line":189},7,[47,191,175],{"class":57},[47,193,194],{"class":53},"|\n",[47,196,198],{"class":49,"line":197},8,[47,199,200],{"class":64},"      slo run \\\n",[47,202,204],{"class":49,"line":203},9,[47,205,206],{"class":64},"        -p \"Review the changes on this branch against main. Focus on bugs,\n",[47,208,210],{"class":49,"line":209},10,[47,211,212],{"class":64},"            missing tests and anything that breaks our conventions in SLO.md.\n",[47,214,216],{"class":49,"line":215},11,[47,217,218],{"class":64},"            End with BLOCKING or OK on its own line.\" \\\n",[47,220,222],{"class":49,"line":221},12,[47,223,224],{"class":64},"        > review.jsonl\n",[47,226,228,230],{"class":49,"line":227},13,[47,229,175],{"class":57},[47,231,232],{"class":64},"jq -r 'select(.kind == \"run_completed\") | .content' review.jsonl | tee review.md\n",[47,234,236,238],{"class":49,"line":235},14,[47,237,175],{"class":57},[47,239,240],{"class":64},"tail -n 1 review.md | grep -q '^OK$'\n",[47,242,244,247],{"class":49,"line":243},15,[47,245,246],{"class":145},"  artifacts",[47,248,149],{"class":57},[47,250,252,255,258,261],{"class":49,"line":251},16,[47,253,254],{"class":145},"    paths",[47,256,257],{"class":57},": [",[47,259,260],{"class":64},"review.md",[47,262,263],{"class":57},"]\n",[14,265,266,267,270,271,274],{},"The final ",[33,268,269],{},"grep"," fails the job when the review ends with ",[33,272,273],{},"BLOCKING",". The same shape works in GitHub Actions or any other runner.",[276,277,279],"note",{"kind":278},"tip",[14,280,281],{},"Asking for a fixed last line (\"End with BLOCKING or OK\") turns a free-text review into something a script can check. It's worth doing for any unattended run.",[18,283,285],{"id":284},"_2-a-morning-report","2. A morning report",[14,287,288,289,292,293,296],{},"For work on your own machine, let your OS run it. On macOS that's ",[33,290,291],{},"launchd",", on Linux ",[33,294,295],{},"cron",", and Slo sets either up for you:",[38,298,300],{"className":40,"code":299,"language":42,"meta":43,"style":43},"slo schedule add \\\n  --name \"Morning test report\" \\\n  --prompt \"Run the full test suite. Summarise failures, flaky tests and anything new since yesterday.\" \\\n  --cron \"0 7 * * 1-5\" \\\n  --cwd ~\u002Fcode\u002Fpayments \\\n  --session-mode fresh\n\nslo schedule install --name \"Morning test report\"\n",[33,301,302,317,327,337,347,357,365,371],{"__ignoreMap":43},[47,303,304,308,311,314],{"class":49,"line":50},[47,305,307],{"class":306},"s_sBn","slo",[47,309,310],{"class":64}," schedule",[47,312,313],{"class":64}," add",[47,315,316],{"class":53}," \\\n",[47,318,319,322,325],{"class":49,"line":142},[47,320,321],{"class":94},"  --name",[47,323,324],{"class":64}," \"Morning test report\"",[47,326,316],{"class":53},[47,328,329,332,335],{"class":49,"line":152},[47,330,331],{"class":94},"  --prompt",[47,333,334],{"class":64}," \"Run the full test suite. Summarise failures, flaky tests and anything new since yesterday.\"",[47,336,316],{"class":53},[47,338,339,342,345],{"class":49,"line":164},[47,340,341],{"class":94},"  --cron",[47,343,344],{"class":64}," \"0 7 * * 1-5\"",[47,346,316],{"class":53},[47,348,349,352,355],{"class":49,"line":172},[47,350,351],{"class":94},"  --cwd",[47,353,354],{"class":64}," ~\u002Fcode\u002Fpayments",[47,356,316],{"class":53},[47,358,359,362],{"class":49,"line":181},[47,360,361],{"class":94},"  --session-mode",[47,363,364],{"class":64}," fresh\n",[47,366,367],{"class":49,"line":189},[47,368,370],{"emptyLinePlaceholder":369},true,"\n",[47,372,373,375,377,380,383],{"class":49,"line":197},[47,374,307],{"class":306},[47,376,310],{"class":64},[47,378,379],{"class":64}," install",[47,381,382],{"class":94}," --name",[47,384,385],{"class":64}," \"Morning test report\"\n",[14,387,388],{},"Each morning on weekdays it runs, then saves a record. Read them with:",[38,390,392],{"className":40,"code":391,"language":42,"meta":43,"style":43},"slo schedule reports --name \"Morning test report\"\n",[33,393,394],{"__ignoreMap":43},[47,395,396,398,400,403,405],{"class":49,"line":50},[47,397,307],{"class":306},[47,399,310],{"class":64},[47,401,402],{"class":64}," reports",[47,404,382],{"class":94},[47,406,385],{"class":64},[14,408,409,412,413,416],{},[33,410,411],{},"fresh"," means each run starts clean. Use ",[33,414,415],{},"continuous"," when you want each run to build on the last, like a running log of a release.",[14,418,419,420,424],{},"See ",[100,421,423],{"href":422},"\u002Fdocs\u002Ffeatures\u002Fschedulers","Schedulers"," for triggers, time zones and the rest.",[18,426,428],{"id":427},"_3-check-in-on-a-long-workflow","3. Check in on a long workflow",[14,430,431],{},"A dynamic workflow can run for hours. Instead of watching it, schedule a check-in that lands in the same session:",[38,433,435],{"className":40,"code":434,"language":42,"meta":43,"style":43},"slo schedule add \\\n  --name \"Refunds check-in\" \\\n  --prompt \"Check the running sub-agents. Report which phases are done,\n            retry anything that stalled, and summarise what's finished.\" \\\n  --cron \"0 * * * *\" \\\n  --session-mode continuous \\\n  --session-reference refunds \\\n  --coalescing-mode latest_by_key \\\n  --coalescing-key refunds\n\nslo schedule install --name \"Refunds check-in\"\n",[33,436,437,447,456,463,470,479,488,498,508,516,520],{"__ignoreMap":43},[47,438,439,441,443,445],{"class":49,"line":50},[47,440,307],{"class":306},[47,442,310],{"class":64},[47,444,313],{"class":64},[47,446,316],{"class":53},[47,448,449,451,454],{"class":49,"line":142},[47,450,321],{"class":94},[47,452,453],{"class":64}," \"Refunds check-in\"",[47,455,316],{"class":53},[47,457,458,460],{"class":49,"line":152},[47,459,331],{"class":94},[47,461,462],{"class":64}," \"Check the running sub-agents. Report which phases are done,\n",[47,464,465,468],{"class":49,"line":164},[47,466,467],{"class":64},"            retry anything that stalled, and summarise what's finished.\"",[47,469,316],{"class":53},[47,471,472,474,477],{"class":49,"line":172},[47,473,341],{"class":94},[47,475,476],{"class":64}," \"0 * * * *\"",[47,478,316],{"class":53},[47,480,481,483,486],{"class":49,"line":181},[47,482,361],{"class":94},[47,484,485],{"class":64}," continuous",[47,487,316],{"class":53},[47,489,490,493,496],{"class":49,"line":189},[47,491,492],{"class":94},"  --session-reference",[47,494,495],{"class":64}," refunds",[47,497,316],{"class":53},[47,499,500,503,506],{"class":49,"line":197},[47,501,502],{"class":94},"  --coalescing-mode",[47,504,505],{"class":64}," latest_by_key",[47,507,316],{"class":53},[47,509,510,513],{"class":49,"line":203},[47,511,512],{"class":94},"  --coalescing-key",[47,514,515],{"class":64}," refunds\n",[47,517,518],{"class":49,"line":209},[47,519,370],{"emptyLinePlaceholder":369},[47,521,522,524,526,528,530],{"class":49,"line":215},[47,523,307],{"class":306},[47,525,310],{"class":64},[47,527,379],{"class":64},[47,529,382],{"class":94},[47,531,532],{"class":64}," \"Refunds check-in\"\n",[14,534,535,536,539,540,543],{},"If the ",[33,537,538],{},"refunds"," session is open in a TUI, the check-in waits in its inbox and runs when the TUI is idle, so two processes never write to one session. If it isn't open, Slo resumes it in the background. ",[33,541,542],{},"latest_by_key"," means that if you're away for a while, you get one pending check-in, not twelve.",[18,545,547],{"id":546},"_4-keep-context-between-steps","4. Keep context between steps",[14,549,550,551,553],{},"Several ",[33,552,113],{}," calls can share one conversation. Give them the same session id:",[38,555,557],{"className":40,"code":556,"language":42,"meta":43,"style":43},"export SLO_SESSION_ID=\"release-$(date +%F)\"\n\nslo run --enable-history -p \"List everything merged since the last tag.\"\nslo run --enable-history -p \"Group those changes into features, fixes and chores.\"\nslo run --enable-history -p \"Write release notes from that grouping.\"\n",[33,558,559,577,581,597,610],{"__ignoreMap":43},[47,560,561,563,566,568,571,574],{"class":49,"line":50},[47,562,54],{"class":53},[47,564,565],{"class":57}," SLO_SESSION_ID",[47,567,61],{"class":53},[47,569,570],{"class":64},"\"release-$(",[47,572,573],{"class":306},"date",[47,575,576],{"class":64}," +%F)\"\n",[47,578,579],{"class":49,"line":142},[47,580,370],{"emptyLinePlaceholder":369},[47,582,583,585,588,591,594],{"class":49,"line":152},[47,584,307],{"class":306},[47,586,587],{"class":64}," run",[47,589,590],{"class":94}," --enable-history",[47,592,593],{"class":94}," -p",[47,595,596],{"class":64}," \"List everything merged since the last tag.\"\n",[47,598,599,601,603,605,607],{"class":49,"line":164},[47,600,307],{"class":306},[47,602,587],{"class":64},[47,604,590],{"class":94},[47,606,593],{"class":94},[47,608,609],{"class":64}," \"Group those changes into features, fixes and chores.\"\n",[47,611,612,614,616,618,620],{"class":49,"line":172},[47,613,307],{"class":306},[47,615,587],{"class":64},[47,617,590],{"class":94},[47,619,593],{"class":94},[47,621,622],{"class":64}," \"Write release notes from that grouping.\"\n",[14,624,625],{},"The third call sees what the first two found.",[276,627,629],{"kind":628},"check",[630,631,632,640,643],"ul",{},[633,634,635,636,639],"li",{},"Unattended runs have credentials and ",[33,637,638],{},"SLO_AUTO_VISUALIZE=0",".",[633,641,642],{},"CI checks a fixed last line or the exit code, not free text.",[633,644,645,646,639],{},"Scheduled jobs are installed and show up in ",[33,647,648],{},"slo schedule list",[650,651,652],"style",{},"html pre.shiki code .sWyjQ, html code.shiki .sWyjQ{--shiki-default:#FF9492}html pre.shiki code .sMAXC, html code.shiki .sMAXC{--shiki-default:#F0F3F6}html pre.shiki code .sTRMh, html code.shiki .sTRMh{--shiki-default:#ADDCFF}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 pre.shiki code .sCcAr, html code.shiki .sCcAr{--shiki-default:#91CBFF}html pre.shiki code .s_sBn, html code.shiki .s_sBn{--shiki-default:#FFB757}html pre.shiki code .sQrFR, html code.shiki .sQrFR{--shiki-default:#BDC4CC}html pre.shiki code .sKpQp, html code.shiki .sKpQp{--shiki-default:#72F088}",{"title":43,"searchDepth":142,"depth":142,"links":654},[655,656,657,658,659],{"id":20,"depth":142,"text":21},{"id":107,"depth":142,"text":108},{"id":284,"depth":142,"text":285},{"id":427,"depth":142,"text":428},{"id":546,"depth":142,"text":547},"Run Slo in CI, on a schedule, and as a check-in on long workflows, without anyone at the keyboard.","md",{},"\u002Fdocs\u002Fguides\u002Fautomate",{"title":5,"description":660},"docs\u002Fguides\u002Fautomate","G9Iky56Pg2QMsdQY-SvAb7E0XVKjjLrjg50A25HpM_I",1791641282712]