loki-mode 7.11.0 → 7.12.0

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/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: loki-mode
3
3
  description: Autonomous spec-to-product system. Triggers on "Loki Mode". Takes a spec (PRD, GitHub issue, OpenAPI doc, etc.) to deployed product via the RARV-C closure loop, with minimal human intervention. Provider-agnostic. Requires --dangerously-skip-permissions flag.
4
4
  ---
5
5
 
6
- # Loki Mode v7.11.0
6
+ # Loki Mode v7.12.0
7
7
 
8
8
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
9
9
 
@@ -381,4 +381,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
381
381
 
382
382
  ---
383
383
 
384
- **v7.11.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
384
+ **v7.12.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 7.11.0
1
+ 7.12.0
package/autonomy/loki CHANGED
@@ -739,6 +739,17 @@ detect_arg_type() {
739
739
  return 0
740
740
  fi
741
741
 
742
+ # R7 (zero-config first run): a one-line brief. An arg that contains
743
+ # whitespace and matched none of the file/issue/path patterns above is a
744
+ # natural-language brief (e.g. "build a todo app"), NOT a PRD path. This is
745
+ # additive: a single-token arg with no whitespace still falls through to
746
+ # "unknown" (PRD-path back-compat) below. The `--brief` flag is the
747
+ # deterministic escape hatch for the rare single-word brief.
748
+ if [[ "$arg" == *[[:space:]]* ]]; then
749
+ echo "brief"
750
+ return 0
751
+ fi
752
+
742
753
  # Fallback: unknown. Caller treats as PRD for backward compat.
743
754
  echo "unknown"
744
755
  }
@@ -752,6 +763,7 @@ cmd_start() {
752
763
  local args=()
753
764
  local prd_file=""
754
765
  local provider=""
766
+ local brief_text="" # R7: explicit one-line brief (--brief "...")
755
767
  local bmad_project_path=""
756
768
  local openspec_change_path=""
757
769
  local mirofish_url=""
@@ -784,6 +796,8 @@ cmd_start() {
784
796
  echo " PRD mode - path ending in .md/.json/.txt/.yaml -> build from PRD"
785
797
  echo " ISSUE mode - GitHub/GitLab/Jira/Azure DevOps URL, owner/repo#N,"
786
798
  echo " PROJ-123, #123, or bare number -> generate PRD from issue"
799
+ echo " BRIEF mode - a quoted one-line description (with spaces) -> fast"
800
+ echo " zero-config first run; visible artifact + proof quickly"
787
801
  echo " no input - analyze current directory, auto-generate PRD"
788
802
  echo ""
789
803
  echo "Arguments:"
@@ -793,6 +807,7 @@ cmd_start() {
793
807
  echo "Explicit mode flags (override auto-detection):"
794
808
  echo " --prd FILE Force PRD mode with FILE"
795
809
  echo " --issue URL|NUM Force issue mode with URL or number"
810
+ echo " --brief \"TEXT\" Force zero-config brief mode (fast first run)"
796
811
  echo ""
797
812
  echo "Options:"
798
813
  echo " --provider NAME AI provider: claude (default), codex, cline, aider"
@@ -816,6 +831,7 @@ cmd_start() {
816
831
  echo " --mirofish-bg Run MiroFish pipeline in background"
817
832
  echo " --no-mirofish Disable MiroFish even if env var is set"
818
833
  echo " --no-plan Skip auto-shown PRD analysis at startup"
834
+ echo " --brief \"TEXT\" Zero-config fast first run from a one-line brief"
819
835
  echo " --yes, -y Skip confirmation prompts (auto-confirm)"
820
836
  echo ""
821
837
  echo "Issue-mode options (only used when input is an ISSUE-REF):"
@@ -836,6 +852,8 @@ cmd_start() {
836
852
  echo ""
837
853
  echo "Examples:"
838
854
  echo " loki start # Interactive, analyze current dir"
855
+ echo " loki start \"build a todo app\" # BRIEF mode (zero-config fast run)"
856
+ echo " loki start --brief \"snake\" # BRIEF mode (single-word escape hatch)"
839
857
  echo " loki start ./prd.md # PRD mode"
840
858
  echo " loki start https://github.com/o/r/issues/42 # ISSUE mode (GitHub)"
841
859
  echo " loki start 123 # ISSUE mode (current repo GitHub issue)"
@@ -1065,6 +1083,22 @@ cmd_start() {
1065
1083
  no_plan=true
1066
1084
  shift
1067
1085
  ;;
1086
+ --brief)
1087
+ # R7: explicit one-line brief (escape hatch for single-word
1088
+ # briefs that detect_arg_type would otherwise treat as a PRD
1089
+ # path). Forces the zero-config first-run brief sub-path.
1090
+ if [[ -n "${2:-}" ]] && [[ "${2:-}" != --* ]]; then
1091
+ brief_text="$2"
1092
+ shift 2
1093
+ else
1094
+ echo -e "${RED}--brief requires a one-line description (e.g., --brief \"build a todo app\")${NC}"
1095
+ exit 1
1096
+ fi
1097
+ ;;
1098
+ --brief=*)
1099
+ brief_text="${1#*=}"
1100
+ shift
1101
+ ;;
1068
1102
  --budget)
1069
1103
  if [[ -n "${2:-}" ]]; then
1070
1104
  if ! echo "$2" | grep -qE '^[0-9]+(\.[0-9]+)?$'; then
@@ -1184,12 +1218,21 @@ cmd_start() {
1184
1218
  done
1185
1219
 
1186
1220
  # v6.84.0: Unified dispatch based on explicit flags or auto-detection
1187
- # Precedence: --issue > --prd > positional auto-detect > LOKI_PRD_FILE env
1221
+ # Precedence: --brief > --issue > --prd > positional auto-detect >
1222
+ # LOKI_PRD_FILE env
1188
1223
  local detected_type=""
1189
- if [ -n "$explicit_mode" ]; then
1224
+ if [ -n "$brief_text" ]; then
1225
+ # R7: explicit --brief always forces the zero-config brief sub-path.
1226
+ detected_type="brief"
1227
+ elif [ -n "$explicit_mode" ]; then
1190
1228
  detected_type="$explicit_mode"
1191
1229
  elif [ -n "$positional_arg" ]; then
1192
1230
  detected_type=$(detect_arg_type "$positional_arg")
1231
+ # R7: a positional one-line brief (whitespace, not a file/issue) maps to
1232
+ # the brief sub-path; capture the text from the positional arg.
1233
+ if [ "$detected_type" = "brief" ]; then
1234
+ brief_text="$positional_arg"
1235
+ fi
1193
1236
  elif [ -n "${LOKI_PRD_FILE:-}" ]; then
1194
1237
  detected_type="prd"
1195
1238
  prd_file="$LOKI_PRD_FILE"
@@ -1229,6 +1272,51 @@ cmd_start() {
1229
1272
  return $?
1230
1273
  fi
1231
1274
 
1275
+ # R7 (zero-config first run): BRIEF mode. The user gave a one-line brief
1276
+ # (`loki start "build a todo app"` or `loki start --brief "..."`). Synthesize
1277
+ # a forward-looking PRD, switch to the lightweight TTFV profile (honest fast:
1278
+ # capped iterations, council off, simple tier, heavy phases off), and mark
1279
+ # LOKI_TTFV=1 so run.sh prints the "what next / go deeper" framing at the
1280
+ # end. Then fall through to the normal flow, which appends prd_file to args
1281
+ # and execs run.sh. This is additive -- nothing here changes the PRD/issue
1282
+ # paths above.
1283
+ if [ "$detected_type" = "brief" ]; then
1284
+ local version
1285
+ version=$(get_version)
1286
+ local _ttfv_max_iter="${LOKI_MAX_ITERATIONS:-3}"
1287
+ mkdir -p "$LOKI_DIR" 2>/dev/null || true
1288
+ local brief_prd="$LOKI_DIR/brief-prd-$$.md"
1289
+ synthesize_brief_prd "$brief_prd" "$brief_text"
1290
+ prd_file="$brief_prd"
1291
+
1292
+ # Apply the shared lightweight profile and flag the TTFV first-run path.
1293
+ # The signal value ("brief") drives the end-of-run wording in run.sh so
1294
+ # the message matches what actually ran (lightweight, council off).
1295
+ set_ttfv_lightweight_profile "$_ttfv_max_iter"
1296
+ export LOKI_TTFV=brief
1297
+ # Skip the heavy auto-plan analysis -- the brief path is the fast path,
1298
+ # and we already printed the upfront framing below.
1299
+ no_plan=true
1300
+
1301
+ echo -e "${BOLD}Loki Mode v$version - Zero-config first run${NC}"
1302
+ echo ""
1303
+ echo -e "${CYAN}Brief:${NC} $brief_text"
1304
+ echo -e "${DIM}Fast first pass: $_ttfv_max_iter iterations max, council off, simple tier.${NC}"
1305
+ echo -e "${DIM}You will get a runnable artifact and a proof-of-run quickly.${NC}"
1306
+ echo -e "${DIM}Go deeper later with: loki start (full RARV-C depth).${NC}"
1307
+ echo -e "${GREEN}Brief PRD written${NC} to $brief_prd"
1308
+ echo ""
1309
+ fi
1310
+
1311
+ # R7: existing-repo no-arg path also gets the TTFV "what next" framing at the
1312
+ # end of the run. Execution here is UNCHANGED (full-depth no-PRD codebase
1313
+ # analysis + generated-PRD-reuse); we only add accurate end-of-run framing.
1314
+ # The signal value ("repo") drives the full-depth wording in run.sh so the
1315
+ # message does not falsely claim a lightweight pass.
1316
+ if [ "$detected_type" = "empty" ] && [ -z "${LOKI_TTFV:-}" ]; then
1317
+ export LOKI_TTFV=repo
1318
+ fi
1319
+
1232
1320
  # PRD mode: positional arg is the PRD file (if not already set via --prd)
1233
1321
  if [ "$detected_type" = "prd" ] && [ -z "$prd_file" ]; then
1234
1322
  prd_file="$positional_arg"
@@ -8847,6 +8935,65 @@ cmd_demo() {
8847
8935
  return $start_exit
8848
8936
  }
8849
8937
 
8938
+ # R7 (zero-config first run): set the lightweight TTFV execution profile.
8939
+ # Shared by `cmd_quick` and the `loki start "<brief>"` brief sub-path so the
8940
+ # fast first pass means the same thing in both: capped iterations, completion
8941
+ # council off, simple complexity tier, heavy phases off. This is HONEST fast --
8942
+ # it genuinely shortens the path to first visible value; it does not fake
8943
+ # progress. Depth is opt-in via a plain `loki start` re-run.
8944
+ # Usage: set_ttfv_lightweight_profile [max_iter]
8945
+ set_ttfv_lightweight_profile() {
8946
+ local max_iter="${1:-${LOKI_MAX_ITERATIONS:-3}}"
8947
+ export LOKI_MAX_ITERATIONS="$max_iter"
8948
+ export LOKI_COMPLEXITY=simple
8949
+ export LOKI_COUNCIL_ENABLED=false
8950
+ export LOKI_PHASE_CODE_REVIEW=false
8951
+ export LOKI_PHASE_PERFORMANCE=false
8952
+ export LOKI_PHASE_ACCESSIBILITY=false
8953
+ export LOKI_PHASE_REGRESSION=false
8954
+ export LOKI_PHASE_UAT=false
8955
+ export LOKI_PHASE_WEB_RESEARCH=false
8956
+ }
8957
+
8958
+ # R7: synthesize a forward-looking PRD from a one-line brief. Writes to a
8959
+ # unique path (caller-provided) and echoes nothing -- the file is the output.
8960
+ # Kept DISTINCT from .loki/generated-prd.md (codebase-analysis artifact) so it
8961
+ # never pollutes the v7.8.1 generated-PRD-reuse signature logic. The brief text
8962
+ # is the project intent; the rest is a minimal scaffold the agent fills in.
8963
+ # Usage: synthesize_brief_prd <output_file> <brief_text>
8964
+ synthesize_brief_prd() {
8965
+ local out_file="$1"
8966
+ local brief_text="$2"
8967
+ local out_dir
8968
+ out_dir="$(dirname "$out_file")"
8969
+ mkdir -p "$out_dir" 2>/dev/null || true
8970
+ cat > "$out_file" << BRIEFEOF
8971
+ # Project Brief
8972
+
8973
+ ## Overview
8974
+ $brief_text
8975
+
8976
+ ## Requirements
8977
+ - Build the smallest working version of the above that a user can see and run.
8978
+ - Prefer a runnable artifact (a page, a CLI, an API endpoint) over scaffolding.
8979
+ - Follow conventional structure for the chosen stack; keep dependencies minimal.
8980
+ - Write a short README describing how to run it.
8981
+
8982
+ ## Success Criteria
8983
+ - A user can run the result and observe the core behavior described above.
8984
+ - No errors on a clean start; the happy path works end to end.
8985
+
8986
+ ## Constraints
8987
+ - This is a fast first pass (zero-config first run). Keep scope tight.
8988
+ - Do not over-engineer; depth and hardening come on a later full run.
8989
+ - No emojis, no em dashes in code, comments, or docs.
8990
+
8991
+ ---
8992
+
8993
+ **Mode:** Brief (zero-config first run, lightweight first pass)
8994
+ BRIEFEOF
8995
+ }
8996
+
8850
8997
  # Quick mode - lightweight single-task execution
8851
8998
  cmd_quick() {
8852
8999
  # v7.6.3 B-11 fix: --help previously fell through to provider invocation
@@ -8934,16 +9081,9 @@ QPRDEOF
8934
9081
  echo -e "${GREEN}Quick PRD generated${NC} at $quick_prd"
8935
9082
  echo ""
8936
9083
 
8937
- # Set lightweight execution environment
8938
- export LOKI_MAX_ITERATIONS="$max_iter"
8939
- export LOKI_COMPLEXITY=simple
8940
- export LOKI_COUNCIL_ENABLED=false
8941
- export LOKI_PHASE_CODE_REVIEW=false
8942
- export LOKI_PHASE_PERFORMANCE=false
8943
- export LOKI_PHASE_ACCESSIBILITY=false
8944
- export LOKI_PHASE_REGRESSION=false
8945
- export LOKI_PHASE_UAT=false
8946
- export LOKI_PHASE_WEB_RESEARCH=false
9084
+ # Set lightweight execution environment (shared TTFV profile -- see
9085
+ # set_ttfv_lightweight_profile; same profile the R7 brief sub-path uses).
9086
+ set_ttfv_lightweight_profile "$max_iter"
8947
9087
 
8948
9088
  # Record start for efficiency tracking
8949
9089
  record_session_start
package/autonomy/run.sh CHANGED
@@ -4121,6 +4121,69 @@ generate_proof_of_run() {
4121
4121
  return 0
4122
4122
  }
4123
4123
 
4124
+ # print_ttfv_next_steps: R7 zero-config first-run "what next / go deeper"
4125
+ # message. The wording MUST match what actually ran, so it branches on the mode:
4126
+ # - brief: a one-line brief ran on the lightweight profile (council off,
4127
+ # simple tier, capped iterations). Proof contains diffs, cost, time
4128
+ # (council verdicts are absent because the council was disabled).
4129
+ # - repo: a no-arg in-repo run analyzed the codebase and ran at full depth
4130
+ # (council on). Proof contains diffs, cost, time, and council
4131
+ # verdicts.
4132
+ # This function only prints; the caller owns the TTY gate. Never fails the run.
4133
+ # Usage: print_ttfv_next_steps <mode> <result>
4134
+ print_ttfv_next_steps() {
4135
+ local mode="${1:-}"
4136
+ local result="${2:-0}"
4137
+ local loki_dir="${TARGET_DIR:-.}/.loki"
4138
+ local proofs_dir="$loki_dir/proofs"
4139
+
4140
+ echo ""
4141
+ echo "============================================================"
4142
+ if [ "$result" = "0" ]; then
4143
+ echo " First pass complete. Here is what you have:"
4144
+ else
4145
+ echo " First pass ended early. Here is what was produced:"
4146
+ fi
4147
+ echo "============================================================"
4148
+ echo ""
4149
+ echo " What I did:"
4150
+ if [ "$mode" = "brief" ]; then
4151
+ echo " - Worked from your one-line brief on a fast, lightweight first"
4152
+ echo " pass (council off, simple tier, capped iterations)."
4153
+ echo " - Generated a proof-of-run (diffs, cost, time)."
4154
+ else
4155
+ echo " - Analyzed your codebase and generated a PRD, then ran a full"
4156
+ echo " first pass (council on, full RARV-C depth)."
4157
+ echo " - Generated a proof-of-run (diffs, cost, time, council verdicts)."
4158
+ fi
4159
+ echo ""
4160
+ echo " See the visible artifact (proof-of-run):"
4161
+ if [ -d "$proofs_dir" ]; then
4162
+ local latest
4163
+ latest=$(ls -1t "$proofs_dir" 2>/dev/null | head -1)
4164
+ if [ -n "$latest" ]; then
4165
+ echo " loki proof open $latest"
4166
+ echo " (or open $proofs_dir/$latest/index.html)"
4167
+ else
4168
+ echo " loki proof list"
4169
+ fi
4170
+ else
4171
+ echo " loki proof list"
4172
+ fi
4173
+ echo ""
4174
+ if [ "$mode" = "brief" ]; then
4175
+ echo " Go deeper (full RARV-C depth, council-gated):"
4176
+ echo " loki start # continue / harden this project"
4177
+ echo " loki start ./prd.md # build from a full PRD"
4178
+ else
4179
+ echo " Next steps:"
4180
+ echo " loki start ./prd.md # build from a full PRD"
4181
+ echo " loki start \"<one line>\" # fast first pass from a brief"
4182
+ fi
4183
+ echo ""
4184
+ return 0
4185
+ }
4186
+
4124
4187
  track_iteration_complete() {
4125
4188
  local iteration="$1"
4126
4189
  local exit_code="${2:-0}"
@@ -13335,6 +13398,15 @@ main() {
13335
13398
  generate_proof_of_run "$result" || true
13336
13399
  fi
13337
13400
 
13401
+ # R7 (zero-config first run): "what next / go deeper" framing. Only when the
13402
+ # CLI flagged this as a TTFV first run and stdout is a TTY, so it stays
13403
+ # silent in CI / pipes and never fires for normal PRD runs. The wording
13404
+ # branches on the mode (brief = lightweight first pass; repo = full-depth
13405
+ # codebase analysis) so the message always matches what actually ran.
13406
+ if [ -n "${LOKI_TTFV:-}" ] && [ -t 1 ]; then
13407
+ print_ttfv_next_steps "${LOKI_TTFV}" "$result" || true
13408
+ fi
13409
+
13338
13410
  # Create PR from agent branch if branch protection was enabled
13339
13411
  create_session_pr
13340
13412
  audit_agent_action "session_stop" "Session ended" "result=$result,iterations=$ITERATION_COUNT"
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "7.11.0"
10
+ __version__ = "7.12.0"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -2,7 +2,7 @@
2
2
 
3
3
  The flagship product of [Autonomi](https://www.autonomi.dev/). Complete installation instructions for all platforms and use cases.
4
4
 
5
- **Version:** v7.11.0
5
+ **Version:** v7.12.0
6
6
 
7
7
  ---
8
8
 
@@ -0,0 +1,137 @@
1
+ # R7: Zero-config killer first run (time-to-first-value)
2
+
3
+ Design note for the R7 release in the competitive-stickiness arc. Worktree
4
+ deliverable for the integrator to cherry-pick. NO version bumps here.
5
+
6
+ ## Goal
7
+
8
+ Convert trials to habits. The #1 acquisition-to-retention gate is the first
9
+ run. Today a blank first run is mediocre and Loki's deep RARV-C / council can
10
+ feel heavy on run 1. R7 = a frictionless first run: a user types
11
+ `loki start "<one line>"` (or `loki start` in an existing repo) and sees a
12
+ VISIBLE valuable artifact in minutes, with depth opt-in later.
13
+
14
+ Honest "fast": we do NOT fake progress. We actually shorten the path by running
15
+ a lightweight execution profile first (capped iterations, completion council
16
+ off, simple complexity tier, heavy phases off) so the first visible artifact
17
+ plus a proof-of-run land quickly. "Go deeper" = re-run plain `loki start` for
18
+ the full RARV-C depth.
19
+
20
+ ## Verified current behavior (real code, traced 2026-06-03)
21
+
22
+ - `cmd_start()` (`autonomy/loki:746`) is the unified entry. It parses args,
23
+ calls `detect_arg_type()` (`autonomy/loki:667`), then dispatches:
24
+ issue -> `cmd_run`; prd -> sets `prd_file`; empty -> no-PRD path; unknown
25
+ -> treated as a PRD path for back-compat.
26
+ - `cmd_start` ends in `_loki_new_session_exec "$RUN_SH" ...` (`autonomy/loki:1678`).
27
+ Every branch of `_loki_new_session_exec` (`autonomy/loki:167-186`) uses
28
+ `exec`, so NOTHING after that line in `cmd_start` runs. Any end-of-run
29
+ message must live in `run.sh`, not after the exec in `cmd_start`.
30
+ - `cmd_quick()` (`autonomy/loki:8849`) already synthesizes a PRD from a
31
+ one-line task and sets the lightweight profile
32
+ (`LOKI_MAX_ITERATIONS=3`, `LOKI_COMPLEXITY=simple`,
33
+ `LOKI_COUNCIL_ENABLED=false`, heavy phases off), then execs `run.sh`.
34
+ - No-PRD + generated-PRD-reuse (v7.8.1): in `run.sh` around line 11102,
35
+ `decide_generated_prd_action()` (`run.sh:4032`) returns reuse|update|generate
36
+ for the no-arg in-repo path; signature persisted by
37
+ `persist_prd_signature_if_present()` (`run.sh:4064`).
38
+ - Proof-of-run (R1): `generate_proof_of_run()` (`run.sh:4101`) wraps
39
+ `autonomy/lib/proof-generator.py`. It runs at session end (`run.sh:13312`)
40
+ on both success and failure, gated only by `LOKI_PROOF` (NOT by council
41
+ state), writing `.loki/proofs/<run_id>/{proof.json,index.html}`. Viewable
42
+ via `loki proof list` / `loki proof open <id>` (Bun-routed, `bin/loki:119`).
43
+
44
+ ### The exact gap R7 closes (traced, not assumed)
45
+
46
+ `loki start "build a todo app"` TODAY:
47
+ 1. `detect_arg_type("build a todo app")` returns `unknown` (has spaces, no
48
+ extension, not a file, not an issue ref).
49
+ 2. The PRD-not-found guard at `autonomy/loki:1243` and `:1268` only fires for
50
+ `*.md|*.json|*.txt|*.yaml|*.yml`, so a brief with spaces slips past.
51
+ 3. `prd_file="build a todo app"` is passed to `run.sh`, which fails:
52
+ `[ERROR] PRD file not found: build a todo app`.
53
+
54
+ So the one-line-brief path is broken today. R7 makes it work. This is ADDITIVE:
55
+ no existing valid input (`.md` PRD, issue ref, single-token name) changes
56
+ behavior.
57
+
58
+ ## Design (additive, no behavior change to existing inputs)
59
+
60
+ 1. `detect_arg_type`: add a `brief` return ONLY for args that contain
61
+ whitespace and match none of the file/issue/path patterns. A single-token
62
+ `unknown` arg still falls back to PRD path (back-compat preserved).
63
+ 2. `--brief "<text>"` explicit flag: deterministic escape hatch for the rare
64
+ single-word brief (e.g. `loki start --brief "snake"`).
65
+ 3. Shared helper `synthesize_brief_prd <file> <text>`: factored so `cmd_quick`
66
+ and the new brief path write the same forward-looking PRD. The brief PRD is
67
+ written to `.loki/brief-prd-$$.md` -- DISTINCT from `.loki/generated-prd.md`
68
+ so it never pollutes the v7.8.1 generated-PRD-reuse signature logic
69
+ (generated-prd is for codebase analysis of an existing repo; brief is a
70
+ forward spec).
71
+ 4. `cmd_start` brief sub-path: set the lightweight TTFV profile (same env as
72
+ quick), synthesize the brief PRD, set `LOKI_TTFV=brief`, then continue
73
+ through the normal exec path. Upfront framing ("fast first pass") is printed
74
+ BEFORE the exec.
75
+ 5. `cmd_start` no-arg in-repo path: UNCHANGED execution (existing no-PRD +
76
+ reuse, full RARV-C depth), but set `LOKI_TTFV=repo` so the end-of-run
77
+ what-next framing appears.
78
+ 6. `run.sh` end-of-session: after proof generation, when `LOKI_TTFV` is set and
79
+ stdout is a TTY, call `print_ttfv_next_steps <mode> <result>`. The wording
80
+ BRANCHES on mode so the message always matches what actually ran:
81
+ - `brief`: lightweight first pass, council off; proof has diffs/cost/time
82
+ (NO council verdicts, because the council was disabled).
83
+ - `repo`: full-depth codebase analysis, council on; proof has
84
+ diffs/cost/time/council verdicts.
85
+ Both point at `loki proof list` / `loki proof open` (the visible artifact)
86
+ and the depth opt-in. Gated so it is silent in CI / pipes and never fires
87
+ for normal PRD runs. Factored into `print_ttfv_next_steps` so it is
88
+ unit-testable.
89
+
90
+ Honesty note: the `brief` message intentionally does NOT advertise "council
91
+ verdicts" because brief mode runs with the council off (`_collect_council` in
92
+ proof-generator.py finds no council state, so that proof section is blank on the
93
+ brief path). The `repo` message claims verdicts because the full-depth path runs
94
+ the council. This keeps the end-of-run summary truthful per the no-fabrication
95
+ rule.
96
+
97
+ ### Why fast is honest
98
+
99
+ The brief path uses the same lightweight profile `cmd_quick` already ships:
100
+ 3 iterations max, council off, simple tier, heavy phases (perf, a11y,
101
+ regression, UAT, web-research) off. That genuinely shortens the path to first
102
+ visible value. We do not print fake progress or claim work that did not happen;
103
+ the proof-of-run is generated from real `.loki/` state. Depth is opt-in: the
104
+ end-of-run message tells the user to re-run plain `loki start` (or
105
+ `loki start <prd.md>`) for the full council-gated build.
106
+
107
+ ## Parity (bash + Bun)
108
+
109
+ `loki start` and `loki quick` are NOT in the Bun shim allowlist
110
+ (`bin/loki:119`), so dispatch is bash-only by design; this change is bash-only
111
+ for the CLI surface. The runtime pieces it reuses are already shared across
112
+ routes: `proof-generator.py` (one implementation, both routes) and the no-PRD /
113
+ generated-PRD-reuse path in `run.sh` (both routes source run.sh). No Bun CLI
114
+ change is required for parity.
115
+
116
+ ## Files
117
+
118
+ - `autonomy/loki`: `detect_arg_type` brief return; `--brief` flag;
119
+ `synthesize_brief_prd` helper; `cmd_quick` refactor to use it; `cmd_start`
120
+ brief sub-path + `LOKI_TTFV` wiring; help text.
121
+ - `autonomy/run.sh`: end-of-session TTFV what-next block.
122
+ - `tests/cli/test_zero_config_first_run.sh`: new test suite.
123
+
124
+ ## Tests (no paid runs; mock via early exit)
125
+
126
+ Following `tests/cli/test_start_run_unified.sh`: extract `detect_arg_type` and
127
+ `synthesize_brief_prd` in a subshell and assert on them; force `cmd_start` to
128
+ exit before `run.sh` boots via `--provider nonexistent-provider`.
129
+
130
+ - `detect_arg_type("build a todo app")` = `brief`; single tokens still `unknown`;
131
+ `.md` still `prd`; issue refs still `issue`; empty still `empty`.
132
+ - `synthesize_brief_prd` writes a PRD containing the brief text and TTFV markers.
133
+ - `loki start "<brief>"` enters the brief path (lightweight env, not
134
+ "PRD file not found").
135
+ - `loki start --brief "<one word>"` works.
136
+ - existing-repo no-arg path still routes to no-PRD (unchanged).
137
+ - `loki start <prd.md>` (real PRD) still routes to PRD mode (no regression).
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- var N7=Object.defineProperty;var k7=(K)=>K;function D7(K,$){this[K]=k7.bind(null,$)}var v=(K,$)=>{for(var Q in $)N7(K,Q,{get:$[Q],enumerable:!0,configurable:!0,set:D7.bind($,Q)})};var E=(K,$)=>()=>(K&&($=K(K=0)),$);var $1=import.meta.require;var z0={};v(z0,{lokiDir:()=>w,homeLokiDir:()=>v1,findRepoRootForVersion:()=>y1,REPO_ROOT:()=>c});import{resolve as p,dirname as b1}from"path";import{fileURLToPath as C7}from"url";import{existsSync as O1}from"fs";import{homedir as h7}from"os";function b7(){let K=Z0;for(let $=0;$<6;$++){if(O1(p(K,"VERSION"))&&O1(p(K,"autonomy/run.sh")))return K;let Q=b1(K);if(Q===K)break;K=Q}return p(Z0,"..","..","..")}function y1(K){let $=K;for(let Q=0;Q<6;Q++){if(O1(p($,"VERSION"))&&O1(p($,"autonomy/run.sh")))return $;let X=b1($);if(X===$)break;$=X}return p(K,"..","..","..")}function w(){return process.env.LOKI_DIR??p(process.cwd(),".loki")}function v1(){return p(h7(),".loki")}var Z0,c;var g=E(()=>{Z0=b1(C7(import.meta.url));c=b7()});import{readFileSync as y7}from"fs";import{resolve as v7,dirname as g7}from"path";import{fileURLToPath as m7}from"url";function T1(){if(r!==null)return r;let K="7.11.0";if(typeof K==="string"&&K.length>0)return r=K,r;try{let $=g7(m7(import.meta.url)),Q=y1($);r=y7(v7(Q,"VERSION"),"utf-8").trim()}catch{r="unknown"}return r}var r=null;var g1=E(()=>{g()});var V0={};v(V0,{runOrThrow:()=>f7,run:()=>N,commandVersion:()=>p7,commandExists:()=>y,ShellError:()=>m1});async function N(K,$={}){let Q=Bun.spawn({cmd:[...K],stdout:"pipe",stderr:"pipe",env:$.env?{...process.env,...$.env}:process.env,cwd:$.cwd}),X,Z;if($.timeoutMs&&$.timeoutMs>0)X=setTimeout(()=>{try{Q.kill("SIGTERM")}catch{}Z=setTimeout(()=>{try{Q.kill("SIGKILL")}catch{}},2000)},$.timeoutMs);try{let[z,H,U]=await Promise.all([new Response(Q.stdout).text(),new Response(Q.stderr).text(),Q.exited]);return{stdout:z,stderr:H,exitCode:U}}finally{if(X)clearTimeout(X);if(Z)clearTimeout(Z)}}async function f7(K,$={}){let Q=await N(K,$);if(Q.exitCode!==0)throw new m1(`command failed (${Q.exitCode}): ${K.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function y(K){let $=u7(K),Q=await N(["sh","-c",`command -v ${$}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function u7(K){if(!/^[A-Za-z0-9._/-]+$/.test(K))throw Error(`refused to shell-escape suspect token: ${K}`);return K}async function p7(K,$="--version"){if(!await y(K))return null;let X=await N([K,$],{timeoutMs:5000});if(X.exitCode!==0)return null;return((X.stdout||X.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var m1;var l=E(()=>{m1=class m1 extends Error{message;exitCode;stdout;stderr;constructor(K,$,Q,X){super(K);this.message=K;this.exitCode=$;this.stdout=Q;this.stderr=X;this.name="ShellError"}}});function d(K){return c7?"":K}var c7,A,h,x,u6,_,k,D,V;var o=E(()=>{c7=(process.env.NO_COLOR??"").length>0;A=d("\x1B[0;31m"),h=d("\x1B[0;32m"),x=d("\x1B[1;33m"),u6=d("\x1B[0;34m"),_=d("\x1B[0;36m"),k=d("\x1B[1m"),D=d("\x1B[2m"),V=d("\x1B[0m")});import{existsSync as e7}from"fs";async function Q1(){if(U1!==void 0)return U1;let K="/opt/homebrew/bin/python3.12";if(e7(K))return U1=K,K;let $=await y("python3.12");if($)return U1=$,$;let Q=await y("python3");return U1=Q,Q}async function t(K,$={}){let Q=await Q1();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return N([Q,"-c",K],$)}var U1;var q1=E(()=>{l()});var A0={};v(A0,{runStatus:()=>B5});import{existsSync as C,readFileSync as Z1,readdirSync as G0,statSync as B0}from"fs";import{resolve as S,basename as Z5}from"path";import{homedir as z5}from"os";async function V5(){if(await y("jq"))return!0;return process.stdout.write(`${A}Error: jq is required but not installed.${V}
2
+ var N7=Object.defineProperty;var k7=(K)=>K;function D7(K,$){this[K]=k7.bind(null,$)}var v=(K,$)=>{for(var Q in $)N7(K,Q,{get:$[Q],enumerable:!0,configurable:!0,set:D7.bind($,Q)})};var E=(K,$)=>()=>(K&&($=K(K=0)),$);var $1=import.meta.require;var z0={};v(z0,{lokiDir:()=>w,homeLokiDir:()=>v1,findRepoRootForVersion:()=>y1,REPO_ROOT:()=>c});import{resolve as p,dirname as b1}from"path";import{fileURLToPath as C7}from"url";import{existsSync as O1}from"fs";import{homedir as h7}from"os";function b7(){let K=Z0;for(let $=0;$<6;$++){if(O1(p(K,"VERSION"))&&O1(p(K,"autonomy/run.sh")))return K;let Q=b1(K);if(Q===K)break;K=Q}return p(Z0,"..","..","..")}function y1(K){let $=K;for(let Q=0;Q<6;Q++){if(O1(p($,"VERSION"))&&O1(p($,"autonomy/run.sh")))return $;let X=b1($);if(X===$)break;$=X}return p(K,"..","..","..")}function w(){return process.env.LOKI_DIR??p(process.cwd(),".loki")}function v1(){return p(h7(),".loki")}var Z0,c;var g=E(()=>{Z0=b1(C7(import.meta.url));c=b7()});import{readFileSync as y7}from"fs";import{resolve as v7,dirname as g7}from"path";import{fileURLToPath as m7}from"url";function T1(){if(r!==null)return r;let K="7.12.0";if(typeof K==="string"&&K.length>0)return r=K,r;try{let $=g7(m7(import.meta.url)),Q=y1($);r=y7(v7(Q,"VERSION"),"utf-8").trim()}catch{r="unknown"}return r}var r=null;var g1=E(()=>{g()});var V0={};v(V0,{runOrThrow:()=>f7,run:()=>N,commandVersion:()=>p7,commandExists:()=>y,ShellError:()=>m1});async function N(K,$={}){let Q=Bun.spawn({cmd:[...K],stdout:"pipe",stderr:"pipe",env:$.env?{...process.env,...$.env}:process.env,cwd:$.cwd}),X,Z;if($.timeoutMs&&$.timeoutMs>0)X=setTimeout(()=>{try{Q.kill("SIGTERM")}catch{}Z=setTimeout(()=>{try{Q.kill("SIGKILL")}catch{}},2000)},$.timeoutMs);try{let[z,H,U]=await Promise.all([new Response(Q.stdout).text(),new Response(Q.stderr).text(),Q.exited]);return{stdout:z,stderr:H,exitCode:U}}finally{if(X)clearTimeout(X);if(Z)clearTimeout(Z)}}async function f7(K,$={}){let Q=await N(K,$);if(Q.exitCode!==0)throw new m1(`command failed (${Q.exitCode}): ${K.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function y(K){let $=u7(K),Q=await N(["sh","-c",`command -v ${$}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function u7(K){if(!/^[A-Za-z0-9._/-]+$/.test(K))throw Error(`refused to shell-escape suspect token: ${K}`);return K}async function p7(K,$="--version"){if(!await y(K))return null;let X=await N([K,$],{timeoutMs:5000});if(X.exitCode!==0)return null;return((X.stdout||X.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var m1;var l=E(()=>{m1=class m1 extends Error{message;exitCode;stdout;stderr;constructor(K,$,Q,X){super(K);this.message=K;this.exitCode=$;this.stdout=Q;this.stderr=X;this.name="ShellError"}}});function d(K){return c7?"":K}var c7,A,h,x,u6,_,k,D,V;var o=E(()=>{c7=(process.env.NO_COLOR??"").length>0;A=d("\x1B[0;31m"),h=d("\x1B[0;32m"),x=d("\x1B[1;33m"),u6=d("\x1B[0;34m"),_=d("\x1B[0;36m"),k=d("\x1B[1m"),D=d("\x1B[2m"),V=d("\x1B[0m")});import{existsSync as e7}from"fs";async function Q1(){if(U1!==void 0)return U1;let K="/opt/homebrew/bin/python3.12";if(e7(K))return U1=K,K;let $=await y("python3.12");if($)return U1=$,$;let Q=await y("python3");return U1=Q,Q}async function t(K,$={}){let Q=await Q1();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return N([Q,"-c",K],$)}var U1;var q1=E(()=>{l()});var A0={};v(A0,{runStatus:()=>B5});import{existsSync as C,readFileSync as Z1,readdirSync as G0,statSync as B0}from"fs";import{resolve as S,basename as Z5}from"path";import{homedir as z5}from"os";async function V5(){if(await y("jq"))return!0;return process.stdout.write(`${A}Error: jq is required but not installed.${V}
3
3
  `),process.stdout.write(`Install with:
4
4
  `),process.stdout.write(` brew install jq (macOS)
5
5
  `),process.stdout.write(` apt install jq (Debian/Ubuntu)
@@ -667,4 +667,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
667
667
  `),2}default:return process.stderr.write(`Unknown command: ${$}
668
668
  `),process.stderr.write(S7),2}}process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var R6=await x6(Bun.argv.slice(2));process.exit(R6);
669
669
 
670
- //# debugId=27611F09F626D9E564756E2164756E21
670
+ //# debugId=255812AF20A1A7F564756E2164756E21
package/mcp/__init__.py CHANGED
@@ -57,4 +57,4 @@ try:
57
57
  except ImportError:
58
58
  __all__ = ['mcp']
59
59
 
60
- __version__ = '7.11.0'
60
+ __version__ = '7.12.0'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loki-mode",
3
- "version": "7.11.0",
3
+ "version": "7.12.0",
4
4
  "description": "Loki Mode by Autonomi. Autonomous spec-to-product system: takes a PRD, GitHub issue, OpenAPI/JSON/YAML, or one-line brief to a deployed app via the RARV-C closure loop with 11 quality gates. Provider-agnostic (Claude Code, OpenAI Codex, Cline, Aider).",
5
5
  "keywords": [
6
6
  "agent",