loki-mode 5.29.0 → 5.31.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/README.md CHANGED
@@ -82,8 +82,44 @@ jobs:
82
82
  github_token: ${{ secrets.GITHUB_TOKEN }}
83
83
  mode: review # review, fix, or test
84
84
  provider: claude # claude, codex, or gemini
85
- max_iterations: 3 # higher = more thorough
86
- budget_limit: '5.00' # max cost in USD
85
+ max_iterations: 3 # sets LOKI_MAX_ITERATIONS env var
86
+ budget_limit: '5.00' # max cost in USD (maps to --budget flag)
87
+ env:
88
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
89
+ ```
90
+
91
+ **Prerequisites:**
92
+ - An API key for your chosen provider (set as a repository secret):
93
+ - Claude: `ANTHROPIC_API_KEY`
94
+ - Codex: `OPENAI_API_KEY`
95
+ - Gemini: `GOOGLE_API_KEY`
96
+ - The action automatically installs `loki-mode` and `@anthropic-ai/claude-code` (for the Claude provider)
97
+
98
+ **Action Inputs:**
99
+
100
+ | Input | Default | Description |
101
+ |-------|---------|-------------|
102
+ | `mode` | `review` | `review`, `fix`, or `test` |
103
+ | `provider` | `claude` | `claude`, `codex`, or `gemini` |
104
+ | `budget_limit` | `5.00` | Max cost in USD (maps to `--budget` CLI flag) |
105
+ | `budget` | | Alias for `budget_limit` |
106
+ | `max_iterations` | `3` | Sets `LOKI_MAX_ITERATIONS` env var |
107
+ | `github_token` | (required) | GitHub token for PR comments |
108
+ | `prd_file` | | Path to PRD file relative to repo root |
109
+ | `auto_confirm` | `true` | Skip confirmation prompts (always true in CI) |
110
+ | `install_claude` | `true` | Auto-install Claude Code CLI if not present |
111
+ | `node_version` | `20` | Node.js version |
112
+
113
+ **Using with a PRD file (fix/test modes):**
114
+
115
+ ```yaml
116
+ - uses: asklokesh/loki-mode@v5
117
+ with:
118
+ mode: fix
119
+ prd_file: 'docs/my-prd.md'
120
+ github_token: ${{ secrets.GITHUB_TOKEN }}
121
+ env:
122
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
87
123
  ```
88
124
 
89
125
  **Modes:**
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: loki-mode
3
3
  description: Multi-agent autonomous startup system. Triggers on "Loki Mode". Takes PRD to deployed product with zero human intervention. Requires --dangerously-skip-permissions flag.
4
4
  ---
5
5
 
6
- # Loki Mode v5.29.0
6
+ # Loki Mode v5.31.0
7
7
 
8
8
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
9
9
 
@@ -62,7 +62,11 @@ REFLECT: Did it work? Update CONTINUITY.md with outcome.
62
62
  v
63
63
  VERIFY: Run tests. Check build. Validate against spec.
64
64
  |
65
- +--[PASS]--> Mark task complete. Return to REASON.
65
+ +--[PASS]--> COMPOUND: If task had novel insight (bug fix, non-obvious solution,
66
+ | reusable pattern), extract to ~/.loki/solutions/{category}/{slug}.md
67
+ | with YAML frontmatter (title, tags, symptoms, root_cause, prevention).
68
+ | See skills/compound-learning.md for format.
69
+ | Then mark task complete. Return to REASON.
66
70
  |
67
71
  +--[FAIL]--> Capture error in "Mistakes & Learnings".
68
72
  Rollback if needed. Retry with new approach.
@@ -119,7 +123,8 @@ These rules are ABSOLUTE. Violating them is a critical failure.
119
123
  ```
120
124
  BOOTSTRAP ──[project initialized]──> DISCOVERY
121
125
  DISCOVERY ──[PRD analyzed, requirements clear]──> ARCHITECTURE
122
- ARCHITECTURE ──[design approved, specs written]──> INFRASTRUCTURE
126
+ ARCHITECTURE ──[design approved, specs written]──> DEEPEN_PLAN (standard/complex only)
127
+ DEEPEN_PLAN ──[plan enhanced by 4 research agents]──> INFRASTRUCTURE
123
128
  INFRASTRUCTURE ──[cloud/DB ready]──> DEVELOPMENT
124
129
  DEVELOPMENT ──[features complete, unit tests pass]──> QA
125
130
  QA ──[all tests pass, security clean]──> DEPLOYMENT
@@ -177,6 +182,8 @@ GROWTH ──[continuous improvement loop]──> GROWTH
177
182
  - Debugging? Load troubleshooting.md
178
183
  - Deploying? Load production.md
179
184
  - Parallel features? Load parallel-workflows.md
185
+ - Architecture planning? Load compound-learning.md (deepen-plan)
186
+ - Post-verification? Load compound-learning.md (knowledge extraction)
180
187
  3. Read the selected module(s)
181
188
  4. Execute with that context
182
189
  5. When task category changes: Load new modules (old context discarded)
@@ -260,4 +267,4 @@ Auto-detected or force with `LOKI_COMPLEXITY`:
260
267
 
261
268
  ---
262
269
 
263
- **v5.29.0 | Demo, quick mode, init, cost dashboard, 12 templates, GitHub Action | ~270 lines core**
270
+ **v5.31.0 | Shell completions, GitHub Action enhancements, auto-confirm | ~280 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 5.29.0
1
+ 5.31.0
package/autonomy/loki CHANGED
@@ -317,7 +317,9 @@ show_help() {
317
317
  echo " voice [cmd] Voice input for PRD creation (status|listen|dictate|speak|start)"
318
318
  echo " import Import GitHub issues as tasks"
319
319
  echo " config [cmd] Manage configuration (show|init|edit|path)"
320
+ echo " completions [bash|zsh] Output shell completion scripts"
320
321
  echo " memory [cmd] Cross-project learnings (list|show|search|stats)"
322
+ echo " compound [cmd] Knowledge compounding (list|show|search|run|stats)"
321
323
  echo " council [cmd] Completion council (status|verdicts|convergence|force-review|report)"
322
324
  echo " dogfood Show self-development statistics"
323
325
  echo " reset [target] Reset session state (all|retries|failed)"
@@ -388,12 +390,22 @@ cmd_start() {
388
390
  echo " --sandbox Run in Docker sandbox"
389
391
  echo " --skip-memory Skip loading memory context at startup"
390
392
  echo " --budget USD Cost budget limit (auto-pause when exceeded)"
393
+ echo " --yes, -y Skip confirmation prompts (auto-confirm)"
394
+ echo ""
395
+ echo "Environment Variables:"
396
+ echo " LOKI_PRD_FILE Path to PRD file (alternative to positional arg)"
397
+ echo " LOKI_AUTO_CONFIRM Set to 'true' to skip confirmation prompts"
398
+ echo " CI When 'true', auto-confirms prompts"
399
+ echo " LOKI_MAX_ITERATIONS Max iteration count"
400
+ echo " LOKI_BUDGET_LIMIT Cost budget limit in USD"
391
401
  echo ""
392
402
  echo "Examples:"
393
403
  echo " loki start # Interactive or resume existing"
394
404
  echo " loki start ./prd.md # Start with PRD file"
395
405
  echo " loki start ./prd.md --parallel # Parallel mode with worktrees"
396
406
  echo " loki start --provider codex # Use OpenAI Codex CLI"
407
+ echo " loki start --yes # Skip confirmation prompt"
408
+ echo " LOKI_PRD_FILE=./prd.md loki start # PRD via env var"
397
409
  exit 0
398
410
  ;;
399
411
  --provider)
@@ -443,6 +455,10 @@ cmd_start() {
443
455
  export LOKI_SKIP_MEMORY=true
444
456
  shift
445
457
  ;;
458
+ --yes|-y)
459
+ export LOKI_AUTO_CONFIRM=true
460
+ shift
461
+ ;;
446
462
  --budget)
447
463
  if [[ -n "${2:-}" ]]; then
448
464
  if ! echo "$2" | grep -qE '^[0-9]+(\.[0-9]+)?$'; then
@@ -476,19 +492,29 @@ cmd_start() {
476
492
  esac
477
493
  done
478
494
 
495
+ # Support LOKI_PRD_FILE environment variable as fallback
496
+ if [ -z "$prd_file" ] && [ -n "${LOKI_PRD_FILE:-}" ]; then
497
+ prd_file="$LOKI_PRD_FILE"
498
+ fi
499
+
479
500
  if [ -n "$prd_file" ]; then
480
501
  args+=("$prd_file")
481
502
  else
482
503
  # No PRD file specified -- warn and confirm before consuming API credits
483
- echo -e "${YELLOW}Warning: No PRD file specified.${NC}"
484
- echo "Loki Mode will start autonomous execution in the current directory"
485
- echo "without a requirements document."
486
- echo ""
487
- echo -e "This will consume API credits. Continue? [y/N] \c"
488
- read -r confirm
489
- if [[ ! "$confirm" =~ ^[Yy] ]]; then
490
- echo "Aborted. Usage: loki start <path-to-prd.md>"
491
- exit 0
504
+ # Auto-confirm in CI environments or when LOKI_AUTO_CONFIRM is set
505
+ if [[ "${LOKI_AUTO_CONFIRM:-}" == "true" ]] || [[ "${CI:-}" == "true" ]]; then
506
+ echo -e "${YELLOW}Warning: No PRD file specified. Auto-confirming (CI mode).${NC}"
507
+ else
508
+ echo -e "${YELLOW}Warning: No PRD file specified.${NC}"
509
+ echo "Loki Mode will start autonomous execution in the current directory"
510
+ echo "without a requirements document."
511
+ echo ""
512
+ echo -e "This will consume API credits. Continue? [y/N] \c"
513
+ read -r confirm
514
+ if [[ ! "$confirm" =~ ^[Yy] ]]; then
515
+ echo "Aborted. Usage: loki start <path-to-prd.md>"
516
+ exit 0
517
+ fi
492
518
  fi
493
519
  fi
494
520
 
@@ -3546,6 +3572,9 @@ main() {
3546
3572
  memory)
3547
3573
  cmd_memory "$@"
3548
3574
  ;;
3575
+ compound)
3576
+ cmd_compound "$@"
3577
+ ;;
3549
3578
  council)
3550
3579
  cmd_council "$@"
3551
3580
  ;;
@@ -3564,6 +3593,9 @@ main() {
3564
3593
  version|--version|-v)
3565
3594
  cmd_version
3566
3595
  ;;
3596
+ completions)
3597
+ cmd_completions "$@"
3598
+ ;;
3567
3599
  help|--help|-h)
3568
3600
  show_help
3569
3601
  ;;
@@ -3841,9 +3873,13 @@ for filename in ['patterns.jsonl', 'mistakes.jsonl', 'successes.jsonl']:
3841
3873
  local type="${2:-}"
3842
3874
 
3843
3875
  if [ -z "$type" ]; then
3844
- echo -e "${YELLOW}This will delete ALL cross-project learnings.${NC}"
3845
- echo -n "Are you sure? (yes/no): "
3846
- read -r confirm
3876
+ if [[ "${LOKI_AUTO_CONFIRM:-}" == "true" ]] || [[ "${CI:-}" == "true" ]]; then
3877
+ confirm="yes"
3878
+ else
3879
+ echo -e "${YELLOW}This will delete ALL cross-project learnings.${NC}"
3880
+ echo -n "Are you sure? (yes/no): "
3881
+ read -r confirm
3882
+ fi
3847
3883
  if [ "$confirm" = "yes" ]; then
3848
3884
  rm -rf "$learnings_dir"
3849
3885
  mkdir -p "$learnings_dir"
@@ -4541,6 +4577,282 @@ except Exception as e:
4541
4577
  esac
4542
4578
  }
4543
4579
 
4580
+ # Knowledge Compounding - Structured Solutions (v5.30.0)
4581
+ # Inspired by Compound Engineering Plugin's docs/solutions/ with YAML frontmatter
4582
+ cmd_compound() {
4583
+ local subcommand="${1:-help}"
4584
+ shift 2>/dev/null || true
4585
+
4586
+ local solutions_dir="${HOME}/.loki/solutions"
4587
+
4588
+ case "$subcommand" in
4589
+ list|ls)
4590
+ echo -e "${BOLD}Compound Solutions${NC}"
4591
+ echo ""
4592
+
4593
+ if [ ! -d "$solutions_dir" ]; then
4594
+ echo " No solutions yet. Solutions are created automatically during"
4595
+ echo " Loki sessions or manually with 'loki compound run'."
4596
+ echo ""
4597
+ echo " Location: $solutions_dir"
4598
+ return
4599
+ fi
4600
+
4601
+ local total=0
4602
+ for category in security performance architecture testing debugging deployment general; do
4603
+ local cat_dir="$solutions_dir/$category"
4604
+ if [ -d "$cat_dir" ]; then
4605
+ local count=$(find "$cat_dir" -name "*.md" 2>/dev/null | wc -l | tr -d ' ')
4606
+ if [ "$count" -gt 0 ]; then
4607
+ printf " %-16s ${GREEN}%d${NC} solutions\n" "$category" "$count"
4608
+ total=$((total + count))
4609
+ fi
4610
+ fi
4611
+ done
4612
+
4613
+ if [ "$total" -eq 0 ]; then
4614
+ echo " No solutions yet."
4615
+ else
4616
+ echo ""
4617
+ echo " Total: ${total} solutions"
4618
+ fi
4619
+ echo ""
4620
+ echo " Location: $solutions_dir"
4621
+ echo ""
4622
+ echo " Use 'loki compound show <category>' to view solutions"
4623
+ ;;
4624
+
4625
+ show)
4626
+ local category="${1:-}"
4627
+ if [ -z "$category" ]; then
4628
+ echo -e "${RED}Error: Specify a category${NC}"
4629
+ echo "Categories: security, performance, architecture, testing, debugging, deployment, general"
4630
+ return 1
4631
+ fi
4632
+
4633
+ local cat_dir="$solutions_dir/$category"
4634
+ if [ ! -d "$cat_dir" ]; then
4635
+ echo "No solutions in category: $category"
4636
+ return
4637
+ fi
4638
+
4639
+ echo -e "${BOLD}Solutions: $category${NC}"
4640
+ echo ""
4641
+
4642
+ for file in "$cat_dir"/*.md; do
4643
+ [ -f "$file" ] || continue
4644
+ # Extract title from YAML frontmatter
4645
+ local title=$(grep '^title:' "$file" 2>/dev/null | head -1 | sed 's/title: *"//;s/"$//')
4646
+ local confidence=$(grep '^confidence:' "$file" 2>/dev/null | head -1 | sed 's/confidence: *//')
4647
+ local project=$(grep '^source_project:' "$file" 2>/dev/null | head -1 | sed 's/source_project: *"//;s/"$//')
4648
+ echo -e " ${GREEN}*${NC} ${title:-$(basename "$file" .md)}"
4649
+ [ -n "$confidence" ] && echo -e " confidence: ${confidence} project: ${project:-unknown}"
4650
+ done
4651
+ echo ""
4652
+ ;;
4653
+
4654
+ search)
4655
+ local query="${1:-}"
4656
+ if [ -z "$query" ]; then
4657
+ echo -e "${RED}Error: Specify a search query${NC}"
4658
+ echo "Usage: loki compound search <query>"
4659
+ return 1
4660
+ fi
4661
+
4662
+ echo -e "${BOLD}Searching solutions for: ${query}${NC}"
4663
+ echo ""
4664
+
4665
+ if [ ! -d "$solutions_dir" ]; then
4666
+ echo "No solutions directory found."
4667
+ return
4668
+ fi
4669
+
4670
+ local found=0
4671
+ while IFS= read -r file; do
4672
+ local title=$(grep '^title:' "$file" 2>/dev/null | head -1 | sed 's/title: *"//;s/"$//')
4673
+ local category=$(grep '^category:' "$file" 2>/dev/null | head -1 | sed 's/category: *//')
4674
+ echo -e " [${CYAN}${category}${NC}] ${title:-$(basename "$file" .md)}"
4675
+ echo -e " ${DIM}${file}${NC}"
4676
+ found=$((found + 1))
4677
+ done < <(grep -rl "$query" "$solutions_dir" 2>/dev/null || true)
4678
+
4679
+ if [ "$found" -eq 0 ]; then
4680
+ echo " No solutions matching: $query"
4681
+ else
4682
+ echo ""
4683
+ echo " Found: ${found} solutions"
4684
+ fi
4685
+ ;;
4686
+
4687
+ run)
4688
+ echo -e "${BOLD}Compounding learnings into solutions...${NC}"
4689
+ echo ""
4690
+
4691
+ local learnings_dir="${HOME}/.loki/learnings"
4692
+ if [ ! -d "$learnings_dir" ]; then
4693
+ echo " No learnings directory found at: $learnings_dir"
4694
+ echo " Run a Loki session first to generate learnings."
4695
+ return
4696
+ fi
4697
+
4698
+ python3 << 'COMPOUND_RUN_SCRIPT'
4699
+ import json, os, re
4700
+ from datetime import datetime, timezone
4701
+ from collections import defaultdict
4702
+ learnings_dir = os.path.expanduser("~/.loki/learnings")
4703
+ solutions_dir = os.path.expanduser("~/.loki/solutions")
4704
+ CATEGORIES = ["security", "performance", "architecture", "testing", "debugging", "deployment", "general"]
4705
+ CATEGORY_KEYWORDS = {
4706
+ "security": ["auth", "login", "password", "token", "injection", "xss", "csrf", "cors", "secret", "encrypt", "permission"],
4707
+ "performance": ["cache", "query", "n+1", "memory", "leak", "slow", "timeout", "pool", "index", "optimize", "bundle"],
4708
+ "architecture": ["pattern", "solid", "coupling", "abstraction", "module", "interface", "design", "refactor", "structure"],
4709
+ "testing": ["test", "mock", "fixture", "coverage", "assert", "spec", "e2e", "playwright", "jest", "flaky"],
4710
+ "debugging": ["debug", "error", "trace", "log", "stack", "crash", "exception", "breakpoint", "inspect"],
4711
+ "deployment": ["deploy", "docker", "ci", "cd", "pipeline", "kubernetes", "nginx", "ssl", "domain", "env", "config"],
4712
+ }
4713
+ def load_jsonl(filepath):
4714
+ entries = []
4715
+ if not os.path.exists(filepath): return entries
4716
+ with open(filepath, 'r') as f:
4717
+ for line in f:
4718
+ try:
4719
+ entry = json.loads(line)
4720
+ if 'description' in entry: entries.append(entry)
4721
+ except: continue
4722
+ return entries
4723
+ def classify_category(description):
4724
+ desc_lower = description.lower()
4725
+ scores = {cat: sum(1 for kw in kws if kw in desc_lower) for cat, kws in CATEGORY_KEYWORDS.items()}
4726
+ best = max(scores, key=scores.get)
4727
+ return best if scores[best] > 0 else "general"
4728
+ def slugify(text):
4729
+ return re.sub(r'[^a-z0-9]+', '-', text.lower().strip()).strip('-')[:80]
4730
+ def solution_exists(solutions_dir, title_slug):
4731
+ for cat in CATEGORIES:
4732
+ cat_dir = os.path.join(solutions_dir, cat)
4733
+ if os.path.exists(cat_dir) and os.path.exists(os.path.join(cat_dir, f"{title_slug}.md")):
4734
+ return True
4735
+ return False
4736
+ patterns = load_jsonl(os.path.join(learnings_dir, "patterns.jsonl"))
4737
+ mistakes = load_jsonl(os.path.join(learnings_dir, "mistakes.jsonl"))
4738
+ successes = load_jsonl(os.path.join(learnings_dir, "successes.jsonl"))
4739
+ print(f" Loaded: {len(patterns)} patterns, {len(mistakes)} mistakes, {len(successes)} successes")
4740
+ grouped = defaultdict(list)
4741
+ for entry in patterns + mistakes + successes:
4742
+ grouped[classify_category(entry.get('description', ''))].append(entry)
4743
+ created = 0
4744
+ now = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
4745
+ for category, entries in grouped.items():
4746
+ if len(entries) < 2: continue
4747
+ cat_dir = os.path.join(solutions_dir, category)
4748
+ os.makedirs(cat_dir, exist_ok=True)
4749
+ best_entry = max(entries, key=lambda e: len(e.get('description', '')))
4750
+ title = best_entry['description'][:120]
4751
+ slug = slugify(title)
4752
+ if solution_exists(solutions_dir, slug): continue
4753
+ all_words = ' '.join(e.get('description', '') for e in entries).lower()
4754
+ tags = []
4755
+ for kw_list in CATEGORY_KEYWORDS.values():
4756
+ for kw in kw_list:
4757
+ if kw in all_words and kw not in tags: tags.append(kw)
4758
+ tags = tags[:8]
4759
+ symptoms = [e.get('description', '')[:200] for e in entries
4760
+ if any(w in e.get('description', '').lower() for w in ['error', 'fail', 'bug', 'crash', 'issue'])][:4]
4761
+ if not symptoms: symptoms = [entries[0].get('description', '')[:200]]
4762
+ solution_lines = [f"- {e.get('description', '')}" for e in entries
4763
+ if not any(w in e.get('description', '').lower() for w in ['error', 'fail', 'bug', 'crash'])]
4764
+ if not solution_lines: solution_lines = [f"- {entries[0].get('description', '')}"]
4765
+ project = best_entry.get('project', os.path.basename(os.getcwd()))
4766
+ filepath = os.path.join(cat_dir, f"{slug}.md")
4767
+ with open(filepath, 'w') as f:
4768
+ f.write(f"---\ntitle: \"{title}\"\ncategory: {category}\ntags: [{', '.join(tags)}]\nsymptoms:\n")
4769
+ for s in symptoms: f.write(f' - "{s}"\n')
4770
+ f.write(f'root_cause: "Identified from {len(entries)} related learnings"\n')
4771
+ f.write(f'prevention: "See solution details below"\nconfidence: {min(0.5 + 0.1 * len(entries), 0.95):.2f}\n')
4772
+ f.write(f'source_project: "{project}"\ncreated: "{now}"\napplied_count: 0\n---\n\n')
4773
+ f.write("## Solution\n\n" + '\n'.join(solution_lines) + '\n\n')
4774
+ f.write(f"## Context\n\nCompounded from {len(entries)} learnings from project: {project}\n")
4775
+ created += 1
4776
+ print(f" Created: {category}/{slug}.md")
4777
+ if created > 0: print(f"\n Compounded {created} new solution files to {solutions_dir}")
4778
+ else: print(" No new solutions to compound (need 2+ related learnings per category)")
4779
+ COMPOUND_RUN_SCRIPT
4780
+ ;;
4781
+
4782
+ stats)
4783
+ echo -e "${BOLD}Compound Solution Statistics${NC}"
4784
+ echo ""
4785
+
4786
+ if [ ! -d "$solutions_dir" ]; then
4787
+ echo " No solutions directory found."
4788
+ return
4789
+ fi
4790
+
4791
+ local total=0
4792
+ local newest=""
4793
+ local oldest=""
4794
+
4795
+ for category in security performance architecture testing debugging deployment general; do
4796
+ local cat_dir="$solutions_dir/$category"
4797
+ if [ -d "$cat_dir" ]; then
4798
+ local count=$(find "$cat_dir" -name "*.md" 2>/dev/null | wc -l | tr -d ' ')
4799
+ total=$((total + count))
4800
+ fi
4801
+ done
4802
+
4803
+ echo " Total solutions: ${total}"
4804
+
4805
+ if [ "$total" -gt 0 ]; then
4806
+ # Find newest and oldest
4807
+ newest=$(find "$solutions_dir" -name "*.md" -exec stat -f '%m %N' {} \; 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2-)
4808
+ oldest=$(find "$solutions_dir" -name "*.md" -exec stat -f '%m %N' {} \; 2>/dev/null | sort -n | head -1 | cut -d' ' -f2-)
4809
+
4810
+ if [ -n "$newest" ]; then
4811
+ local newest_title=$(grep '^title:' "$newest" 2>/dev/null | head -1 | sed 's/title: *"//;s/"$//')
4812
+ echo " Newest: ${newest_title:-$(basename "$newest" .md)}"
4813
+ fi
4814
+ if [ -n "$oldest" ]; then
4815
+ local oldest_title=$(grep '^title:' "$oldest" 2>/dev/null | head -1 | sed 's/title: *"//;s/"$//')
4816
+ echo " Oldest: ${oldest_title:-$(basename "$oldest" .md)}"
4817
+ fi
4818
+ fi
4819
+
4820
+ echo ""
4821
+ echo " Location: $solutions_dir"
4822
+ ;;
4823
+
4824
+ help|--help|-h)
4825
+ echo -e "${BOLD}loki compound${NC} - Knowledge compounding system"
4826
+ echo ""
4827
+ echo "Extracts structured solutions from cross-project learnings."
4828
+ echo "Solutions are stored as markdown files with YAML frontmatter"
4829
+ echo "at ~/.loki/solutions/{category}/ and fed back into future planning."
4830
+ echo ""
4831
+ echo "Usage: loki compound <command>"
4832
+ echo ""
4833
+ echo "Commands:"
4834
+ echo " list List all solutions by category"
4835
+ echo " show <category> Show solutions in a category"
4836
+ echo " search <query> Search across all solutions"
4837
+ echo " run Manually compound current learnings into solutions"
4838
+ echo " stats Solution statistics"
4839
+ echo " help Show this help"
4840
+ echo ""
4841
+ echo "Categories: security, performance, architecture, testing,"
4842
+ echo " debugging, deployment, general"
4843
+ echo ""
4844
+ echo "Solutions are created automatically at session end and"
4845
+ echo "loaded during the REASON phase for relevant tasks."
4846
+ ;;
4847
+
4848
+ *)
4849
+ echo -e "${RED}Unknown compound command: $subcommand${NC}"
4850
+ echo "Run 'loki compound help' for usage."
4851
+ return 1
4852
+ ;;
4853
+ esac
4854
+ }
4855
+
4544
4856
  # Completion Council management
4545
4857
  cmd_council() {
4546
4858
  local subcommand="${1:-status}"
@@ -5608,4 +5920,54 @@ for line in sys.stdin:
5608
5920
  esac
5609
5921
  }
5610
5922
 
5923
+ # Output shell completion scripts
5924
+ cmd_completions() {
5925
+ local shell="${1:-bash}"
5926
+ local skill_dir
5927
+
5928
+ # Find the skill directory (where autonomy/loki is located)
5929
+ skill_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5930
+ local completions_dir="$skill_dir/completions"
5931
+
5932
+ case "$shell" in
5933
+ bash)
5934
+ if [ -f "$completions_dir/loki.bash" ]; then
5935
+ cat "$completions_dir/loki.bash"
5936
+ else
5937
+ echo -e "${RED}Error: Bash completion script not found at $completions_dir/loki.bash${NC}" >&2
5938
+ exit 1
5939
+ fi
5940
+ ;;
5941
+ zsh)
5942
+ if [ -f "$completions_dir/_loki" ]; then
5943
+ cat "$completions_dir/_loki"
5944
+ else
5945
+ echo -e "${RED}Error: Zsh completion script not found at $completions_dir/_loki${NC}" >&2
5946
+ exit 1
5947
+ fi
5948
+ ;;
5949
+ *)
5950
+ echo -e "${BOLD}Loki Shell Completions${NC}"
5951
+ echo ""
5952
+ echo "Output shell completion scripts for bash or zsh."
5953
+ echo ""
5954
+ echo "Usage: loki completions <shell>"
5955
+ echo ""
5956
+ echo "Shells:"
5957
+ echo " bash Bash completion script"
5958
+ echo " zsh Zsh completion script"
5959
+ echo ""
5960
+ echo "Installation:"
5961
+ echo ""
5962
+ echo "Bash:"
5963
+ echo " eval \"\$(loki completions bash)\" >> ~/.bashrc"
5964
+ echo ""
5965
+ echo "Zsh:"
5966
+ echo " eval \"\$(loki completions zsh)\" >> ~/.zshrc"
5967
+ echo ""
5968
+ exit 1
5969
+ ;;
5970
+ esac
5971
+ }
5972
+
5611
5973
  main "$@"