loki-mode 10.6.7 → 10.6.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -9
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/lib/backlog.py +167 -36
- package/autonomy/lib/workspace.py +384 -0
- package/autonomy/lib/workspace_comment.py +91 -0
- package/autonomy/lib/worktree_prep.py +143 -0
- package/autonomy/loki +96 -3
- package/bin/loki +3 -3
- package/completions/_loki +2 -0
- package/completions/loki.bash +1 -2
- package/dashboard/__init__.py +1 -1
- package/dashboard/api_start.py +26 -1
- package/docs/INSTALLATION.md +1 -1
- package/docs/WANG-PRINCIPLES-PLAN.md +1 -1
- package/docs/WORKSPACES.md +36 -0
- package/docs/alternative-installations.md +3 -1
- package/docs/control-plane-container.md +50 -0
- package/docs/dashboard-guide.md +4 -0
- package/docs/dev/architecture-reference.md +4 -0
- package/docs/dev/project-structure.md +1 -1
- package/docs/exit-codes.md +1 -0
- package/docs/slack.md +34 -0
- package/docs/trackers.md +27 -0
- package/docs/v10/BOARD.md +74 -14
- package/docs/v10/CONTROL-PLANE.md +17 -6
- package/docs/v10/D51-PHASE-B.md +3 -1
- package/docs/v10/D61-SPEED.md +11 -2
- package/docs/v10/D63-CARDS.md +354 -0
- package/docs/v10/DECISIONS.md +63 -0
- package/docs/v10/DEPS.md +6 -2
- package/docs/v10/E2E-D65.md +87 -0
- package/docs/v10/HANDOFF-NEXT-WEEK.md +10 -4
- package/docs/v10/PROGRESS.md +63 -0
- package/docs/v10/ROADMAP-D63.md +35 -0
- package/loki-ts/dist/loki.js +612 -556
- package/mcp/__init__.py +1 -1
- package/mcp/server.py +76 -0
- package/mcp/tests/test_v10_tools.py +193 -0
- package/mcp/v10_tools.py +182 -0
- package/package.json +1 -1
- package/packages/control-plane/dist/server.js +131 -9
- package/packages/control-plane/drizzle/0001_group_id.sql +3 -0
- package/packages/control-plane/drizzle/meta/_journal.json +8 -1
- package/packages/control-plane/src/db/schema.ts +3 -0
- package/packages/control-plane/src/server/answer.ts +33 -0
- package/packages/control-plane/src/server/app.ts +22 -2
- package/packages/control-plane/src/server/auth.ts +51 -0
- package/packages/control-plane/src/server/runs.ts +6 -3
- package/packages/control-plane/src/server/serve.ts +13 -3
- package/packages/control-plane/src/shipper/discover.ts +29 -0
- package/packages/control-plane/ui/dist/assets/{index-BH3LtKcG.css → index-CFfrqCx2.css} +1 -1
- package/packages/control-plane/ui/dist/assets/index-Jt31nrK-.js +114 -0
- package/packages/control-plane/ui/dist/index.html +2 -2
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/web-app/dist/assets/{AdminPage-DyjnUcaP.js → AdminPage-CZKZLuWU.js} +1 -1
- package/web-app/dist/assets/{Avatar-CY0sQNao.js → Avatar-Dcy9kO2E.js} +1 -1
- package/web-app/dist/assets/{Badge-BmwTRu72.js → Badge-DUotUSyx.js} +1 -1
- package/web-app/dist/assets/{Button-BRf5aTlb.js → Button-CFz_zfMZ.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-RR94HuxS.js → CockpitPage-BhRw_oiM.js} +1 -1
- package/web-app/dist/assets/{ComparePage-CFWAuPRO.js → ComparePage-DfnsRTTC.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-4cDADrG-.js → ErrorBoundary-Dn0gUu3D.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-ChPFx2eM.js → EvidenceReceiptPanel-Co-xi282.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-B0TAjyeW.js → GitHubIssuesPanel-CoCpfexq.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-BbszEwW9.js → GitHubPRsPanel-Dg0Eg6F_.js} +1 -1
- package/web-app/dist/assets/{HomePage-DrBgzs1d.js → HomePage-BysxL4mV.js} +2 -2
- package/web-app/dist/assets/{LoginPage-Bu7b2DGz.js → LoginPage-CQ366p_d.js} +1 -1
- package/web-app/dist/assets/{MagicPage-BFEYp631.js → MagicPage-DD7YcbNq.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-eIe2naVR.js → MetricsPage-BYz49xQj.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-BVWYkNt9.js → NotFoundPage-CKs09MeO.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-zmxyu732.js → ProjectPage-Ci2BIA_D.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-Dq5NdCak.js → ProjectsPage-ClwMH0eu.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-CCrJOMe0.js → SettingsPage-Cm0rCX-y.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-n-Ipzp01.js → ShowcasePage-CxvESt8X.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-CP_rjYXK.js → SystemSettingsPage-W_CGYPOY.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-B_P9DepW.js → TeamsPage-feVvRvys.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-h-3A6PQT.js → TemplatesPage-C-pUWMmF.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-pD0nJ1BU.js → TerminalOutput-j5ibjKY3.js} +1 -1
- package/web-app/dist/assets/{activity-ChFwzT-d.js → activity-TTdVYMa_.js} +1 -1
- package/web-app/dist/assets/{bell-BX-eK8Gu.js → bell-DeoTFwpv.js} +1 -1
- package/web-app/dist/assets/{bot-fj5PkPtR.js → bot-B5SghxqU.js} +1 -1
- package/web-app/dist/assets/{check-BGAbHlvD.js → check-k8SzsdbE.js} +1 -1
- package/web-app/dist/assets/{chevron-left-BzFUxHgb.js → chevron-left-DHnEllFz.js} +1 -1
- package/web-app/dist/assets/{circle-alert-BQrg5DWl.js → circle-alert-DW_SLdcB.js} +1 -1
- package/web-app/dist/assets/{clock-CTu9lkVo.js → clock-Bmoaxy09.js} +1 -1
- package/web-app/dist/assets/{cloud-DrIENRiE.js → cloud-eg3tzXTh.js} +1 -1
- package/web-app/dist/assets/{code-xml-PaoVpfur.js → code-xml-VAfXihhD.js} +1 -1
- package/web-app/dist/assets/{database-DMmkAotn.js → database-CY3_-5aK.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-B2LQdBoX.js → dollar-sign-DYC0OLlg.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-Dfv1XXeR.js → file-code-corner-0X3SveKz.js} +1 -1
- package/web-app/dist/assets/{file-plus-D2Wzf2wd.js → file-plus-B_oh_ukl.js} +1 -1
- package/web-app/dist/assets/{globe-DxotVWt8.js → globe-F0tLA8WJ.js} +1 -1
- package/web-app/dist/assets/{hammer-Brfy5ZrJ.js → hammer-DrlvBmfW.js} +1 -1
- package/web-app/dist/assets/{index-BfhHMwi8.js → index-YihVaZAj.js} +3 -3
- package/web-app/dist/assets/{layers-DfxSWDvp.js → layers-CbJfn5UC.js} +1 -1
- package/web-app/dist/assets/{loader-circle-CxIrzNwx.js → loader-circle-CpmOggou.js} +1 -1
- package/web-app/dist/assets/{lock-m6nzhtpU.js → lock-BGJ6QWrI.js} +1 -1
- package/web-app/dist/assets/{package-ri9oE9Jc.js → package-BTmH4Xto.js} +1 -1
- package/web-app/dist/assets/{plus-DWeTAMVV.js → plus-mKQ7hz-8.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-BGMSpaMh.js → refresh-cw-vPetpLsm.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-DD1xBD_b.js → rotate-ccw-DiJ8GFhj.js} +1 -1
- package/web-app/dist/assets/{scroll-text-BCCR_AN9.js → scroll-text-DpPQIlQR.js} +1 -1
- package/web-app/dist/assets/{server-CmMWPIjS.js → server-CiaV4drx.js} +1 -1
- package/web-app/dist/assets/{shield-alert-BZZmBVEJ.js → shield-alert-BaaQqyco.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-OaxbNRXu.js → thumbs-up-2zNCKp0Q.js} +1 -1
- package/web-app/dist/assets/{trash-2-DmcSzTfr.js → trash-2-CiVDx5Co.js} +1 -1
- package/web-app/dist/assets/{trending-down-BmfXLykz.js → trending-down-tcxvw5BH.js} +1 -1
- package/web-app/dist/assets/{trending-up-Djec3jIq.js → trending-up-C2bv2_v_.js} +1 -1
- package/web-app/dist/assets/{upload-BN8dXIlF.js → upload-DS4VPUAp.js} +1 -1
- package/web-app/dist/assets/{usePolling-Cu4yi04I.js → usePolling-JggBcVln.js} +1 -1
- package/web-app/dist/assets/{user-IBI-k10o.js → user-CvavvOxM.js} +1 -1
- package/web-app/dist/index.html +1 -1
- package/packages/control-plane/ui/dist/assets/index-B6EiyukW.js +0 -114
package/autonomy/loki
CHANGED
|
@@ -1630,6 +1630,7 @@ show_help() {
|
|
|
1630
1630
|
echo " start [SPEC] Start a build (PRD file, GitHub/GitLab/Jira/Azure issue, or no arg)"
|
|
1631
1631
|
echo " plan <PRD-file> Dry-run analysis: complexity, cost, execution plan"
|
|
1632
1632
|
echo " backlog <owner/repo> --all|--label X|--issues N,N Run every matching open issue, N in parallel"
|
|
1633
|
+
echo " workspace list | run <name> <ref> Multi-repo runs from loki.yaml workspaces (LOKI_WORKSPACES=0 disables)"
|
|
1633
1634
|
echo " quickstart [idea] Guided first build: setup, idea, template, plan, go"
|
|
1634
1635
|
echo ""
|
|
1635
1636
|
echo "Session:"
|
|
@@ -1782,7 +1783,7 @@ show_help() {
|
|
|
1782
1783
|
echo " syslog telemetry template test tour trigger trust trust-metrics"
|
|
1783
1784
|
echo " ultracode update verify version voice watch watchdog web welcome why"
|
|
1784
1785
|
echo " wiki worktree (wt)"
|
|
1785
|
-
echo " control
|
|
1786
|
+
echo " control"
|
|
1786
1787
|
echo ""
|
|
1787
1788
|
echo "Any command: loki <command> --help"
|
|
1788
1789
|
echo ""
|
|
@@ -1896,7 +1897,74 @@ _loki_dashboard_port_is_ours() {
|
|
|
1896
1897
|
return 1
|
|
1897
1898
|
}
|
|
1898
1899
|
|
|
1900
|
+
# C3: the Control Plane is the default UI. Prints a live loopback URL from
|
|
1901
|
+
# ~/.loki/control/instance.json (pid alive, http loopback only, /health says
|
|
1902
|
+
# service=loki-control), or starts `loki control serve` detached and waits for
|
|
1903
|
+
# it to publish one. Returns 1 when the caller should fall back to the old
|
|
1904
|
+
# dashboard (LOKI_CONTROL_DEFAULT=0, no bun, no python3, server did not start).
|
|
1905
|
+
_loki_control_live_url() {
|
|
1906
|
+
local inst="${HOME}/.loki/control/instance.json" fields pid url health
|
|
1907
|
+
[ -f "$inst" ] || return 1
|
|
1908
|
+
fields=$(python3 - "$inst" 2>/dev/null <<'PY'
|
|
1909
|
+
import json, sys, urllib.parse
|
|
1910
|
+
d = json.load(open(sys.argv[1]))
|
|
1911
|
+
pid, url = d.get("pid"), d.get("url")
|
|
1912
|
+
if not isinstance(pid, int) or isinstance(pid, bool) or not isinstance(url, str):
|
|
1913
|
+
sys.exit(1)
|
|
1914
|
+
u = urllib.parse.urlparse(url)
|
|
1915
|
+
if u.scheme != "http" or u.hostname not in ("127.0.0.1", "localhost", "::1"):
|
|
1916
|
+
sys.exit(1)
|
|
1917
|
+
if u.path not in ("", "/") or u.query or u.fragment or u.params or "@" in u.netloc or "?" in url or "#" in url:
|
|
1918
|
+
sys.exit(1)
|
|
1919
|
+
print(pid, url.rstrip("/"))
|
|
1920
|
+
PY
|
|
1921
|
+
) || return 1
|
|
1922
|
+
pid="${fields%% *}"; url="${fields#* }"
|
|
1923
|
+
kill -0 "$pid" 2>/dev/null || return 1
|
|
1924
|
+
health=$(curl -g -s --max-time 2 "${url}/health" 2>/dev/null) || return 1
|
|
1925
|
+
case "$health" in *'"service"'*'"loki-control"'*) ;; *) return 1 ;; esac
|
|
1926
|
+
printf '%s\n' "$url"
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1929
|
+
_loki_control_ui() {
|
|
1930
|
+
[ "${LOKI_CONTROL_DEFAULT:-1}" = "0" ] && return 1
|
|
1931
|
+
local url="" open_it=1 arg i
|
|
1932
|
+
for arg in "$@"; do [ "$arg" = "--no-open" ] && open_it=0; done
|
|
1933
|
+
if [ "${LOKI_HEADLESS:-0}" = "1" ] || [ "${LOKI_NO_BROWSER:-0}" = "1" ]; then open_it=0; fi
|
|
1934
|
+
command -v python3 >/dev/null 2>&1 || return 1
|
|
1935
|
+
url=$(_loki_control_live_url) || url=""
|
|
1936
|
+
if [ -z "$url" ]; then
|
|
1937
|
+
if ! command -v bun >/dev/null 2>&1; then
|
|
1938
|
+
echo "loki: the Control Plane needs bun (https://bun.sh); using the classic dashboard." >&2
|
|
1939
|
+
return 1
|
|
1940
|
+
fi
|
|
1941
|
+
local cli="$SKILL_DIR/loki-ts/dist/loki.js" cdir="${HOME}/.loki/control" spid
|
|
1942
|
+
[ -f "$cli" ] || cli="$SKILL_DIR/loki-ts/src/cli.ts"
|
|
1943
|
+
mkdir -p "$cdir" && chmod 700 "$cdir" 2>/dev/null || true
|
|
1944
|
+
LOKI_CONTROL=1 LOKI_NO_BROWSER=1 nohup bun "$cli" control serve >"$cdir/serve.log" 2>&1 </dev/null &
|
|
1945
|
+
spid=$!
|
|
1946
|
+
echo "$spid" > "$cdir/serve.pid" 2>/dev/null || true
|
|
1947
|
+
for i in $(seq 1 100); do
|
|
1948
|
+
url=$(_loki_control_live_url) && break
|
|
1949
|
+
url=""
|
|
1950
|
+
kill -0 "$spid" 2>/dev/null || break
|
|
1951
|
+
sleep 0.1
|
|
1952
|
+
done
|
|
1953
|
+
if [ -z "$url" ]; then
|
|
1954
|
+
echo "loki: the Control Plane did not start (see $cdir/serve.log); using the classic dashboard." >&2
|
|
1955
|
+
return 1
|
|
1956
|
+
fi
|
|
1957
|
+
fi
|
|
1958
|
+
if [ "$open_it" = "1" ]; then
|
|
1959
|
+
loki_open_url "$url" || echo "$url"
|
|
1960
|
+
else
|
|
1961
|
+
echo "$url"
|
|
1962
|
+
fi
|
|
1963
|
+
return 0
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1899
1966
|
cmd_ui() {
|
|
1967
|
+
_loki_control_ui "$@" && return 0
|
|
1900
1968
|
local port="" pid=""
|
|
1901
1969
|
if [ -f "$DASHBOARD_PID_FILE" ]; then
|
|
1902
1970
|
pid=$(cat "$DASHBOARD_PID_FILE" 2>/dev/null)
|
|
@@ -7324,6 +7392,16 @@ _loki_dashboard_bind_is_safe() {
|
|
|
7324
7392
|
cmd_dashboard() {
|
|
7325
7393
|
local subcommand="${1:-}"
|
|
7326
7394
|
|
|
7395
|
+
# The Control Plane is the default UI; LOKI_CONTROL_DEFAULT=0 restores the classic dashboard.
|
|
7396
|
+
# Only the bare forms are taken over; `start --port ...` and friends keep the classic server.
|
|
7397
|
+
case "$subcommand" in
|
|
7398
|
+
""|start|open)
|
|
7399
|
+
if [ $# -le 1 ] || { [ $# -eq 2 ] && [ "$2" = "--no-open" ]; }; then
|
|
7400
|
+
_loki_control_ui "${@:2}" && return 0
|
|
7401
|
+
fi
|
|
7402
|
+
;;
|
|
7403
|
+
esac
|
|
7404
|
+
|
|
7327
7405
|
# If no subcommand provided, show help (backward compatible with old behavior)
|
|
7328
7406
|
if [ -z "$subcommand" ]; then
|
|
7329
7407
|
cmd_dashboard_help
|
|
@@ -12909,6 +12987,16 @@ cmd_config_schema() {
|
|
|
12909
12987
|
loki_config_generate_schema
|
|
12910
12988
|
}
|
|
12911
12989
|
|
|
12990
|
+
# D65: multi-repo workspaces (D51 Phase B). On by default; LOKI_WORKSPACES=0 disables.
|
|
12991
|
+
cmd_workspace() {
|
|
12992
|
+
if [ "${LOKI_WORKSPACES:-}" = "0" ]; then
|
|
12993
|
+
echo -e "${RED}loki workspace is disabled.${NC} Unset LOKI_WORKSPACES (it is set to 0)." >&2
|
|
12994
|
+
return 2
|
|
12995
|
+
fi
|
|
12996
|
+
command -v python3 >/dev/null 2>&1 || { echo -e "${RED}loki workspace: python3 is required${NC}" >&2; return 2; }
|
|
12997
|
+
python3 "$_LOKI_SCRIPT_DIR/lib/workspace.py" "$@"
|
|
12998
|
+
}
|
|
12999
|
+
|
|
12912
13000
|
# D51: headless backlog runner. One v10 issue-mode run per open issue, each in
|
|
12913
13001
|
# its own worktree and branch, at most N in parallel (loki.yaml concurrency).
|
|
12914
13002
|
cmd_backlog() {
|
|
@@ -18692,10 +18780,12 @@ with open(manifest_path, 'w') as f:
|
|
|
18692
18780
|
# usable.
|
|
18693
18781
|
# ---------------------------------------------------------------------------
|
|
18694
18782
|
cmd_verify() {
|
|
18695
|
-
# D48: --pubkey verifies a receipt against a given public key (v10 engine, no ~/.loki needed).
|
|
18783
|
+
# D48: --pubkey FILE or --pubkey=FILE (any position) verifies a receipt against a given public key (v10 engine, no ~/.loki needed).
|
|
18696
18784
|
local _pk_arg
|
|
18697
18785
|
for _pk_arg in "$@"; do
|
|
18698
|
-
|
|
18786
|
+
case "$_pk_arg" in
|
|
18787
|
+
--pubkey|--pubkey=*) LOKI_ENGINE=v10 exec "$_LOKI_SCRIPT_DIR/../bin/loki" verify "$@" ;;
|
|
18788
|
+
esac
|
|
18699
18789
|
done
|
|
18700
18790
|
# --fast: deterministic checks only, in milliseconds. Measured on this repo
|
|
18701
18791
|
# (1,932 tracked files): 298 ms cold, 87 ms warm, 19 ms diff-scoped, against
|
|
@@ -21922,6 +22012,9 @@ main() {
|
|
|
21922
22012
|
backlog)
|
|
21923
22013
|
cmd_backlog "$@"
|
|
21924
22014
|
;;
|
|
22015
|
+
workspace)
|
|
22016
|
+
cmd_workspace "$@"
|
|
22017
|
+
;;
|
|
21925
22018
|
config)
|
|
21926
22019
|
cmd_config "$@"
|
|
21927
22020
|
;;
|
package/bin/loki
CHANGED
|
@@ -354,12 +354,12 @@ case "${LOKI_ENGINE:-$_loki_engine_default}" in
|
|
|
354
354
|
# `loki <ref>`; any other start call (PRD file, flags first, one word) stays legacy.
|
|
355
355
|
start)
|
|
356
356
|
case "${2:-}" in
|
|
357
|
-
*/*\#[0-9]*|http*://*/issues/*|http*://*/browse/*|*" "*) _e10=1; _e10_args=("${@:2}") ;;
|
|
357
|
+
*/*\#[0-9]*|http*://*/issues/*|http*://*/browse/*|jira:*|linear:*|https://linear.app/*/issue/*|*" "*) _e10=1; _e10_args=("${@:2}") ;;
|
|
358
358
|
*) _e10=0 ;;
|
|
359
359
|
esac
|
|
360
360
|
;;
|
|
361
361
|
# http*://*/issues/* also covers GitLab's /-/issues/ URLs.
|
|
362
|
-
*/*\#[0-9]*|http*://*/issues/*|http*://*/browse/*) _e10=1 ;;
|
|
362
|
+
*/*\#[0-9]*|http*://*/issues/*|http*://*/browse/*|jira:*|linear:*|https://linear.app/*/issue/*) _e10=1 ;;
|
|
363
363
|
*" "*) _e10=1 ;;
|
|
364
364
|
# ponytail: a one-word argument stays on the legacy CLI. The telemetry
|
|
365
365
|
# allowlist is not a command registry (estimate, intent, outcomes are
|
|
@@ -567,7 +567,7 @@ fi
|
|
|
567
567
|
# Two-token routes (provider show/list, memory list/index) match on the first
|
|
568
568
|
# token only; the Bun dispatcher handles subcommand routing internally.
|
|
569
569
|
case "${1:-}" in
|
|
570
|
-
version|--version|-v|status|stats|doctor|provider|memory|rollback|internal|kpis|trust|proof|receipt|wiki|crash|control)
|
|
570
|
+
version|--version|-v|status|stats|doctor|provider|memory|rollback|internal|kpis|trust|proof|receipt|wiki|crash|control|contract|slack|answer)
|
|
571
571
|
# v7.5.2: rollback added (wires loki-ts/src/commands/rollback.ts).
|
|
572
572
|
# v7.5.3: internal added for autonomy/run.sh phase1-hooks calls.
|
|
573
573
|
# v7.5.28: kpis added (Phase K MVP: read-only KPI snapshot).
|
package/completions/_loki
CHANGED
|
@@ -206,7 +206,9 @@ function _loki_commands {
|
|
|
206
206
|
'crash:Crash report management'
|
|
207
207
|
'otel:OpenTelemetry management'
|
|
208
208
|
'wiki:Wiki commands'
|
|
209
|
+
'answer:Resume a BLOCKED run with an answer'
|
|
209
210
|
'control:Control plane (preview, LOKI_CONTROL=1)'
|
|
211
|
+
'workspace:Multi-project workspaces (preview, LOKI_WORKSPACES=1)'
|
|
210
212
|
'backlog:Run every matching open issue, N in parallel'
|
|
211
213
|
'explain:Explain Loki concepts'
|
|
212
214
|
'optimize:Optimization commands'
|
package/completions/loki.bash
CHANGED
|
@@ -5,8 +5,7 @@ _loki_completion() {
|
|
|
5
5
|
_init_completion || return
|
|
6
6
|
|
|
7
7
|
# Main subcommands (must match autonomy/loki main case statement)
|
|
8
|
-
local main_commands="start backlog quick monitor demo tour welcome init stop pause resume steer status next ship dashboard web serve api sandbox notify import github issue config provider reset memory compound checkpoint council dogfood projects enterprise secrets cockpit secure own handoff doctor watchdog audit metrics syslog onboard share proof receipt outcomes explain plan report cost estimate kpis stats test ci watch telemetry agent context ctx code run export review optimize heal modernize migrate cluster worktree wt trigger failover remote deploy docker mcp magic assets analyze compliance crash control open otel preview quickstart rc rollback self-update sentrux setup-skill spec state template trust trust-metrics ultracode update verify voice why wiki bench cleanup logs grill docs cp version completions help keys"
|
|
9
|
-
local main_commands="start backlog quick monitor demo tour welcome init stop pause resume steer status next ship dashboard web serve api sandbox notify import github issue intent config provider reset memory compound checkpoint council dogfood projects enterprise secrets cockpit secure own handoff doctor watchdog audit metrics syslog onboard share proof receipt explain plan report cost estimate kpis stats test ci watch telemetry agent context ctx code run export review optimize heal modernize migrate cluster worktree wt trigger failover remote deploy docker mcp magic assets analyze compliance crash control open otel preview quickstart rc rollback self-update sentrux setup-skill spec state template trust trust-metrics ultracode update verify voice why wiki bench cleanup logs grill docs cp version completions help keys"
|
|
8
|
+
local main_commands="start backlog quick monitor demo tour welcome init stop pause resume steer status next ship dashboard web serve api sandbox notify import github issue intent config provider reset memory compound checkpoint council dogfood projects enterprise secrets cockpit secure own handoff doctor watchdog audit metrics syslog onboard share proof receipt outcomes explain plan report cost estimate kpis stats test ci watch telemetry agent context ctx code run export review optimize heal modernize migrate cluster worktree wt trigger failover remote deploy docker mcp magic assets analyze compliance crash control workspace open otel preview quickstart rc rollback self-update sentrux setup-skill spec state template trust trust-metrics ultracode update verify voice why wiki bench cleanup logs grill docs cp version completions help keys answer"
|
|
10
9
|
|
|
11
10
|
# 1. If we are on the first argument (subcommand)
|
|
12
11
|
if [[ $cword -eq 1 ]]; then
|
package/dashboard/__init__.py
CHANGED
package/dashboard/api_start.py
CHANGED
|
@@ -21,6 +21,7 @@ import os
|
|
|
21
21
|
import re
|
|
22
22
|
import shutil
|
|
23
23
|
import subprocess
|
|
24
|
+
import sys
|
|
24
25
|
import threading
|
|
25
26
|
import time
|
|
26
27
|
import urllib.error
|
|
@@ -156,6 +157,25 @@ def _project_dir() -> str:
|
|
|
156
157
|
return os.environ.get("LOKI_PROJECT_DIR") or os.getcwd()
|
|
157
158
|
|
|
158
159
|
|
|
160
|
+
def _autonomy_lib():
|
|
161
|
+
lib = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "autonomy", "lib")
|
|
162
|
+
if lib not in sys.path:
|
|
163
|
+
sys.path.insert(0, lib)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _workspaces_enabled() -> bool:
|
|
167
|
+
"""Same rule as `loki workspace`: on by default, LOKI_WORKSPACES=0 disables."""
|
|
168
|
+
_autonomy_lib()
|
|
169
|
+
import workspace
|
|
170
|
+
return workspace.enabled()
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _worktree_prep():
|
|
174
|
+
_autonomy_lib()
|
|
175
|
+
import worktree_prep
|
|
176
|
+
return worktree_prep
|
|
177
|
+
|
|
178
|
+
|
|
159
179
|
def _prepare_workdir(repo: str, number: int, token: str) -> str:
|
|
160
180
|
"""One git worktree per issue, off the repo's default branch."""
|
|
161
181
|
env = dict(os.environ, GH_TOKEN=token, GIT_TERMINAL_PROMPT="0")
|
|
@@ -180,7 +200,12 @@ def _prepare_workdir(repo: str, number: int, token: str) -> str:
|
|
|
180
200
|
stamp = time.strftime("%Y%m%d%H%M%S")
|
|
181
201
|
wt = _home() / "worktrees" / slug / ("issue-%d-%s" % (number, stamp))
|
|
182
202
|
wt.parent.mkdir(parents=True, exist_ok=True)
|
|
183
|
-
|
|
203
|
+
branch = "loki/backlog-%d-%s" % (number, stamp)
|
|
204
|
+
if _workspaces_enabled():
|
|
205
|
+
# Shared worktree prep (D51-B06): same per-base lock and dep copy as backlog and workspace runs.
|
|
206
|
+
_worktree_prep().prepare_worktree(base, str(wt), branch, base=start)
|
|
207
|
+
return str(wt)
|
|
208
|
+
_git("worktree", "add", "-b", branch, str(wt), start, cwd=base)
|
|
184
209
|
return str(wt)
|
|
185
210
|
|
|
186
211
|
|
package/docs/INSTALLATION.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The flagship product of [Autonomi](https://www.autonomi.dev/). Loki Mode is a spec-driven autonomous builder with a built-in trust layer that takes any spec to a deployed product and verifies completion with evidence (quality gates plus a completion council), not just a "done" claim. Complete installation instructions for all platforms and use cases.
|
|
4
4
|
|
|
5
|
-
**Version:** v10.6.
|
|
5
|
+
**Version:** v10.6.9
|
|
6
6
|
|
|
7
7
|
**Engine note:** `loki "<task>"`, `loki owner/repo#N` and `loki quick` run the Loki 10 engine. `loki start` still routes to the legacy engine, which is being removed (planned work resumes 2026-10-07); prefer `loki owner/repo#N`. See [docs/v10/GUIDE.md](v10/GUIDE.md).
|
|
8
8
|
|
|
@@ -53,7 +53,7 @@ Measured on this machine, not asserted.
|
|
|
53
53
|
| **1 Systems Thinking** | STRONG | 8 quality gates, RARV-C loop, council, Evidence Receipt, dual-route parity enforced by test |
|
|
54
54
|
| **2 Speed** | MEASURED, UNOPTIMISED | agent call = **980s = 96%** of iteration; all gates together = 44s |
|
|
55
55
|
| **3 Reliability** | STRONG, newly so | 73 mutation-proven trust invariants; four gates were shipping broken until v8.38.0 |
|
|
56
|
-
| **4 Extensibility** | STRONG | 5 providers, agent type registry, MCP (
|
|
56
|
+
| **4 Extensibility** | STRONG | 5 providers, agent type registry, MCP (39 tools), plugin marketplace |
|
|
57
57
|
| **5 Feedback Loops / Evals** | **BROKEN** | `cost_usd == 0` on **3 of 5** efficiency records; no eval score for our own harness |
|
|
58
58
|
|
|
59
59
|
**Principle 5 is the gap, and it is the one Wang weights highest.** He states the
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Workspaces: one issue across several repos
|
|
2
|
+
|
|
3
|
+
On by default. Set `LOKI_WORKSPACES=0` to disable. Design: `docs/v10/D51-PHASE-B.md`.
|
|
4
|
+
|
|
5
|
+
Define a group of repos once in `loki.yaml`:
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
workspaces:
|
|
9
|
+
shop:
|
|
10
|
+
repos:
|
|
11
|
+
- {repo: acme/api, path: ~/src/api, setup: "npm ci"}
|
|
12
|
+
- {repo: acme/web, path: ~/src/web, after: [acme/api]}
|
|
13
|
+
integration: {command: "make e2e", timeout_s: 900}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Repos with no pending `after` run in parallel, at most `concurrency` at a time (default 2; set `LOKI_WORKSPACE_CONCURRENCY` to change it).
|
|
17
|
+
|
|
18
|
+
Then:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
loki workspace list
|
|
22
|
+
loki workspace show shop
|
|
23
|
+
loki workspace run shop acme/api#12
|
|
24
|
+
loki workspace status # every recorded run, one row per repo
|
|
25
|
+
loki workspace status <run-id>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- Each repo gets its own git worktree on a `loki/ws-<run-id>-N` branch and its own engine run. Your checkouts are not touched.
|
|
29
|
+
- `after` orders repos: a repo starts once its predecessors succeed. If a predecessor fails, its dependents are SKIPPED.
|
|
30
|
+
- A failing repo does not stop the others (continue and report). The command exits 0 only when every repo succeeded and the integration step did not fail. It exits 3 when the only non-ok outcomes are budget stops (a child exited 3, or a dependent was skipped behind one), and 1 for any other failure. Ctrl-C (SIGINT) stops the recorded child process groups like SIGTERM.
|
|
31
|
+
- The repo that owns the issue ref gets the ref; other repos get a task text naming the ref and the sibling worktree paths as read-only context.
|
|
32
|
+
- After all repos finish, the `integration` command runs once from the run directory with `LOKI_WS_DIR_<OWNER>_<REPO>` pointing at each worktree. A timeout counts as failed. With no integration configured the status is `not_configured`.
|
|
33
|
+
- Evidence is written to `.loki/workspaces/<name>/<run-id>/integration.json`: head SHA per repo, exit code, log sha256. It is not part of the Seal.
|
|
34
|
+
- Without `path`, a repo is cloned to `~/.loki/repos/owner__name`.
|
|
35
|
+
- After the integration step, a PR comment is posted on each repo PR that exists for its run branch, showing the integration status (PASSED, FAILED, TIMEOUT or NOT CONFIGURED) and every head SHA. It uses your own `gh` login or GH_TOKEN, skips silently when there is no PR, never fails the run, and is disabled with `LOKI_WORKSPACE_COMMENT=0`.
|
|
36
|
+
- Backlog (`loki backlog`) and dashboard starts now share the workspace worktree prep: a per-repo lock, a clean start point and copied dependencies. `LOKI_WORKSPACES=0` restores the previous worktree creation (D51-B05, D51-B06).
|
|
@@ -84,11 +84,13 @@ jobs:
|
|
|
84
84
|
|-------|---------|-------------|
|
|
85
85
|
| `mode` | `review` | `review`, `fix`, or `test` |
|
|
86
86
|
| `provider` | `claude` | `claude` (recommended), `cline`, `codex`, `aider`, or `opencode`. `gemini` was REMOVED in v7.5.18. |
|
|
87
|
-
| `budget_limit` | `5.00` | Max cost in USD |
|
|
87
|
+
| `budget_limit` | `5.00` | Max cost in USD (passed to the Loki 10 engine as `--max-cost`) |
|
|
88
88
|
| `max_iterations` | `3` | Max RARV cycles |
|
|
89
89
|
| `github_token` | (required) | GitHub token for PR comments |
|
|
90
90
|
| `prd_file` | | Path to PRD file (for fix/test modes) |
|
|
91
91
|
|
|
92
|
+
**Engine:** every mode runs the Loki 10 engine through `loki start "<task>" --no-pr --provider <name> --max-cost <usd>` (the same path as `loki start owner/repo#N`), with `LOKI_ENGINE=v10`. The PRD file or PR diff is folded into the task text. The action never opens a PR itself (Rule of Two). A run that crosses the cap ends BUDGET_STOP (exit 3). The legacy `--simple` path is no longer used.
|
|
93
|
+
|
|
92
94
|
**Modes:**
|
|
93
95
|
|
|
94
96
|
| Mode | Description |
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Run the Control Plane in a container
|
|
2
|
+
|
|
3
|
+
The Control Plane (run ingest API plus UI) ships as its own small image built
|
|
4
|
+
from `Dockerfile.control-plane`. It serves on port 47821, stores its SQLite
|
|
5
|
+
database under `/data`, runs as a non-root user and contains no secrets.
|
|
6
|
+
|
|
7
|
+
The image binds 0.0.0.0, so `LOKI_CONTROL_TOKEN` is required at run time. Without
|
|
8
|
+
it the server exits 2 before listening. Every `/v1/*` call then needs
|
|
9
|
+
`Authorization: Bearer <token>`. The token is never baked into the image. Set
|
|
10
|
+
`LOKI_CONTROL_ALLOW_INSECURE_BIND=1` only on a trusted private network; the
|
|
11
|
+
server prints a warning when you do.
|
|
12
|
+
|
|
13
|
+
## Docker
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
docker build -f Dockerfile.control-plane -t loki-control-plane .
|
|
17
|
+
docker run -d -p 47821:47821 -e LOKI_CONTROL_TOKEN="$(openssl rand -hex 32)" -v loki-control:/data loki-control-plane
|
|
18
|
+
LOKI_CONTROL_URL=http://localhost:47821 loki control status
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Health: `/health` (liveness) and `/ready` (database check).
|
|
22
|
+
|
|
23
|
+
## Helm
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
helm install loki-control ./deploy/helm/control-plane \
|
|
27
|
+
--namespace loki --create-namespace \
|
|
28
|
+
--set image.repository=<your-registry>/loki-control-plane \
|
|
29
|
+
--set existingSecret=autonomi-secrets \
|
|
30
|
+
--set 'secretKeys={ANTHROPIC_API_KEY}'
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Provider keys are read from an existing Kubernetes Secret you name with
|
|
34
|
+
`existingSecret`; nothing is stored in values. Ingress is off by default
|
|
35
|
+
(`ingress.enabled=true` to turn it on). Keep `replicas: 1` (single SQLite volume).
|
|
36
|
+
|
|
37
|
+
## ECS
|
|
38
|
+
|
|
39
|
+
See `deploy/ecs/README.md` and `deploy/ecs/control-plane-task.json` (Fargate,
|
|
40
|
+
EFS volume, secrets from Secrets Manager ARNs).
|
|
41
|
+
|
|
42
|
+
## Configuration
|
|
43
|
+
|
|
44
|
+
| Variable | Default in image | Meaning |
|
|
45
|
+
| --- | --- | --- |
|
|
46
|
+
| `PORT` | 47821 | listen port |
|
|
47
|
+
| `LOKI_CONTROL_HOST` | 0.0.0.0 | bind address (outside the image: 127.0.0.1) |
|
|
48
|
+
| `LOKI_CONTROL_TOKEN` | none (required) | bearer token for `/v1/*`; required on a non-loopback bind |
|
|
49
|
+
| `LOKI_CONTROL_ALLOW_INSECURE_BIND` | unset | `1` accepts a tokenless non-loopback bind (not recommended) |
|
|
50
|
+
| `LOKI_CONTROL_DB` | /data/control.db | SQLite path |
|
package/docs/dashboard-guide.md
CHANGED
|
@@ -482,3 +482,7 @@ Useful for:
|
|
|
482
482
|
- [Agent Types](../references/agent-types.md) - Agent role definitions
|
|
483
483
|
- [Quality Control](../references/quality-control.md) - Quality gates system
|
|
484
484
|
- [Memory System](../references/memory-system.md) - Memory architecture
|
|
485
|
+
|
|
486
|
+
## Control Plane by default
|
|
487
|
+
|
|
488
|
+
Bare `loki` and `loki dashboard` (also `start` or `open` with no other flags) open the Control Plane. If `~/.loki/control/instance.json` names a live loopback server whose `/health` reports `service=loki-control`, that URL is reused; otherwise `loki control serve` is started detached and its PID is recorded in `~/.loki/control/serve.pid`. With `LOKI_HEADLESS=1`, `LOKI_NO_BROWSER=1` or `--no-open` the URL is printed and no browser is opened. Without bun, Loki prints one line naming bun and uses the classic dashboard. Set `LOKI_CONTROL_DEFAULT=0` to always use the classic dashboard. Multi-repo `loki workspace` is on by default; `LOKI_WORKSPACES=0` disables it.
|
|
@@ -97,3 +97,7 @@ Default-on in the Bun runner (see `CHANGELOG.md` v7.x entries; documented in `sk
|
|
|
97
97
|
- `LOKI_HANDOFF_MD` -- write a structured handoff doc before iteration close.
|
|
98
98
|
|
|
99
99
|
These knobs together implement the RARV-C (closure) loop: findings -> override council -> learnings -> handoff. Reference: `skills/quality-gates.md`, `CHANGELOG.md` entries from v7.x for default-on flip and override-council semantics.
|
|
100
|
+
|
|
101
|
+
## Worktree substrate (autonomy/lib/worktree_prep.py)
|
|
102
|
+
|
|
103
|
+
`prepare_worktree(source_repo, dest, branch, setup=None, base=None)` creates an isolated git worktree and returns `{path, base_sha, deps, left_out_changes}`. The start point is `origin/HEAD` after a fetch (when a remote exists), else HEAD. Uncommitted edits in the source checkout are never carried or stashed; their count is reported as `left_out_changes`. An fcntl lock at `~/.loki/repos/<slug>.lock` covers fetch and worktree add. Dependencies: a `setup` command run in the worktree, else a copy-on-write copy of ignored top-level `node_modules`, `.venv`, `venv`, `vendor` (refused as "copy unsafe, declare setup" if it holds absolute symlinks or editable finders), else `none`. CLI: `python3 autonomy/lib/worktree_prep.py SRC DEST BRANCH [--setup CMD] [--base REF]` prints the result as JSON. Not yet wired into backlog or the UI.
|
|
@@ -91,7 +91,7 @@ Line counts approximate; re-run `wc -l` for exact.
|
|
|
91
91
|
| `memory/storage.py` | ~2,000 | File-based memory backend |
|
|
92
92
|
| `memory/engine.py` | ~1,600 | Memory orchestrator |
|
|
93
93
|
| `memory/consolidation.py` | ~1,100 | Episodic-to-semantic pipeline |
|
|
94
|
-
| `mcp/server.py` | ~2,700 | MCP server (
|
|
94
|
+
| `mcp/server.py` | ~2,700 | MCP server (39 tools: 31 in-file + 7 magic + 1 gated managed; +3 resources, 2 prompts) |
|
|
95
95
|
| `providers/loader.sh` | ~185 | Provider loader |
|
|
96
96
|
|
|
97
97
|
### Key Function Lookup
|
package/docs/exit-codes.md
CHANGED
|
@@ -104,6 +104,7 @@ never the local JWKS. Exits: 0 VERIFIED, 1 TAMPERED, 2 UNCHECKED (kid does not
|
|
|
104
104
|
match the key, or the key file is unusable), 3 UNSIGNED (a receipt with no
|
|
105
105
|
signature is refused even with `--allow-unsigned`, because the caller asked for a
|
|
106
106
|
signature check), 4 run outcome not verified (checked before UNSIGNED).
|
|
107
|
+
`--pubkey` may come before or after the run-id and may be written `--pubkey=FILE`; `--pubkey` with no file or an empty `--pubkey=`, a repeated `--pubkey`, an unknown option, or more than one run-id exits 2.
|
|
107
108
|
|
|
108
109
|
An early draft spec listed `1=BLOCKED, 2=CONCERNS`. That ordering was rejected:
|
|
109
110
|
it is not used anywhere, it has no consumers, and it inverts the
|
package/docs/slack.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Two-way Slack
|
|
2
|
+
|
|
3
|
+
On by default. Set `LOKI_SLACK_INBOUND=0` to disable the inbound handler (`loki slack serve` then exits 2).
|
|
4
|
+
|
|
5
|
+
Without `SLACK_BOT_TOKEN` or `SLACK_SIGNING_SECRET`, `loki slack serve` prints one line naming both and exits 2 without binding a port.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
export SLACK_BOT_TOKEN=... # from env only, never stored by Loki
|
|
9
|
+
export SLACK_SIGNING_SECRET=...
|
|
10
|
+
loki slack serve --port 3000 # binds 127.0.0.1 unless --host is given
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Point the Slack Events API request URL at this server through a tunnel or reverse proxy you control.
|
|
14
|
+
|
|
15
|
+
## What it does
|
|
16
|
+
|
|
17
|
+
- `@loki <issue ref or task text>` in a channel starts a Loki 10 run (it launches `bin/loki "<task>"`; the text must be at least two words and must not start with `-`, otherwise the bot replies asking you to describe the task, so a lone word like `reset` can never reach a legacy subcommand) and replies in the thread with the run id.
|
|
18
|
+
- When the run ends BLOCKED, the question is posted in the same thread. A reply in that thread starts a follow-up run with your answer added to the original task (v10 has no in-place resume, BLOCKED is terminal).
|
|
19
|
+
- Runs are launched through the repo `bin/loki` with the two Slack secrets removed from the child environment and `LOKI_NO_BROWSER=1` set. A failed Slack post logs one redacted line to stderr.
|
|
20
|
+
- Every request is verified with the Slack signature (HMAC sha256 over `v0:timestamp:body`, constant-time compare, timestamps older than 5 minutes are rejected). Retried events are deduplicated.
|
|
21
|
+
|
|
22
|
+
## Who can start a run
|
|
23
|
+
|
|
24
|
+
Set `LOKI_SLACK_ALLOWED_USERS` to a comma-separated list of Slack user IDs (for example `U012ABC,U034DEF`). A mention or a BLOCKED-thread answer from any other user is rejected with a short thread reply and nothing is spawned. When it is unset, anyone who can mention the bot can start a run, and `loki slack serve` prints one startup line saying so.
|
|
25
|
+
|
|
26
|
+
Limits: task text over 64 KB is rejected with "task too long" and no run starts. If a run cannot be launched, the thread gets a generic message and the detail (which may include local paths) is logged to stderr only. `--port` must be a whole number (an empty value exits 2).
|
|
27
|
+
|
|
28
|
+
## App manifest scopes
|
|
29
|
+
|
|
30
|
+
Bot token scopes: `app_mentions:read`, `chat:write`, `channels:history` (and `groups:history` for private channels, `im:history` for DMs).
|
|
31
|
+
|
|
32
|
+
Subscribe to bot events: `app_mention`, `message.channels` (plus `message.groups` for private channels).
|
|
33
|
+
|
|
34
|
+
Outbound notifications (PR opened, BLOCKED, finished) are separate and use `LOKI_SLACK_WEBHOOK_URL`.
|
package/docs/trackers.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Jira and Linear intake
|
|
2
|
+
|
|
3
|
+
Loki 10 can start a run from a Jira or Linear issue. This is intake only: the issue is fetched once, before any model runs, and normalized into the same `issue.json` GitHub intake writes (with a `source` field of `jira` or `linear`). Loki does not write back to the tracker or sync status.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
loki jira:PROJ-123
|
|
7
|
+
loki linear:ENG-42
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Credentials (environment only)
|
|
11
|
+
|
|
12
|
+
- Jira: `JIRA_EMAIL`, `JIRA_API_TOKEN` and `JIRA_BASE_URL` (for example `https://acme.atlassian.net`). `JIRA_BASE_URL` may be omitted when you pass an `atlassian.net` browse URL.
|
|
13
|
+
- Linear: `LINEAR_API_KEY`.
|
|
14
|
+
|
|
15
|
+
A missing variable stops the run with an error that names it. A Linear HTTP 401, or a GraphQL response with errors and no data, also names `LINEAR_API_KEY`.
|
|
16
|
+
|
|
17
|
+
## Self-hosted Jira
|
|
18
|
+
|
|
19
|
+
`<JIRA_BASE_URL>/browse/KEY` is accepted as a ref only when its origin equals the origin of `JIRA_BASE_URL`. A browse URL on any other host is not treated as a tracker ref.
|
|
20
|
+
|
|
21
|
+
## Kill switch
|
|
22
|
+
|
|
23
|
+
`LOKI_TRACKER_INTAKE=0` disables Jira and Linear refs entirely; they are then treated as ordinary text.
|
|
24
|
+
|
|
25
|
+
## Safety
|
|
26
|
+
|
|
27
|
+
Issue text is untrusted input. It is passed to the run as data and never grants tool authority.
|