loki-mode 6.59.0 → 6.61.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/autonomy/run.sh CHANGED
@@ -8125,6 +8125,70 @@ except Exception:
8125
8125
  " 2>/dev/null || true)
8126
8126
  fi
8127
8127
 
8128
+ # MiroFish market validation context injection (if available)
8129
+ local mirofish_context=""
8130
+ if [[ -f ".loki/mirofish-context.json" ]]; then
8131
+ mirofish_context=$(python3 -c "
8132
+ import json
8133
+ try:
8134
+ with open('.loki/mirofish-context.json') as f:
8135
+ data = json.load(f)
8136
+ parts = ['MIROFISH MARKET VALIDATION:']
8137
+ adv = data.get('analysis', {})
8138
+ summary = adv.get('overall_sentiment', '')
8139
+ score = adv.get('sentiment_score', 0)
8140
+ conf = adv.get('confidence', '')
8141
+ rec = adv.get('recommendation', '')
8142
+ if summary:
8143
+ parts.append(f'Overall: {summary} (score={score}, confidence={conf}, recommendation={rec})')
8144
+ concerns = adv.get('key_concerns', [])
8145
+ if concerns:
8146
+ parts.append('Key Concerns: ' + '; '.join(c[:200] for c in concerns[:5]))
8147
+ rankings = adv.get('feature_rankings', [])
8148
+ if rankings:
8149
+ ranked = ', '.join(f'{r[\"feature\"]}={r[\"reception_score\"]}' for r in rankings[:5])
8150
+ parts.append(f'Feature Reception: {ranked}')
8151
+ quotes = adv.get('notable_quotes', [])
8152
+ if quotes:
8153
+ parts.append('Agent Quotes: ' + ' | '.join(q[:150] for q in quotes[:3]))
8154
+ parts.append('NOTE: MiroFish results are advisory only. They do NOT override Completion Council or quality gates.')
8155
+ print(' '.join(parts))
8156
+ except Exception:
8157
+ pass
8158
+ " 2>/dev/null || true)
8159
+ elif [[ -f ".loki/mirofish/pipeline-state.json" ]]; then
8160
+ mirofish_context=$(python3 -c "
8161
+ import json, os
8162
+ try:
8163
+ with open('.loki/mirofish/pipeline-state.json') as f:
8164
+ state = json.load(f)
8165
+ status = state.get('status', 'unknown')
8166
+ stage = state.get('current_stage', 0)
8167
+ pid = state.get('pid', 0)
8168
+ alive = False
8169
+ if pid:
8170
+ try:
8171
+ os.kill(pid, 0)
8172
+ alive = True
8173
+ except OSError:
8174
+ pass
8175
+ if status == 'running' and alive:
8176
+ s3 = state.get('stages', {}).get('3_simulation', {})
8177
+ progress = ''
8178
+ if s3.get('status') == 'running':
8179
+ cr = s3.get('current_round', 0)
8180
+ tr = s3.get('total_rounds', 0)
8181
+ if tr:
8182
+ progress = f' (simulation round {cr}/{tr})'
8183
+ print(f'MIROFISH_STATUS: Market validation running stage {stage}/4{progress}. Advisory will appear when complete.')
8184
+ elif status == 'failed':
8185
+ error = state.get('error', 'unknown')[:200]
8186
+ print(f'MIROFISH_STATUS: Market validation failed at stage {stage}: {error}. Proceeding without.')
8187
+ except Exception:
8188
+ pass
8189
+ " 2>/dev/null || true)
8190
+ fi
8191
+
8128
8192
  # Degraded providers with small models need simplified prompts
8129
8193
  # Full RARV/SDLC instructions overwhelm models < 30B parameters
8130
8194
  if [ "${PROVIDER_DEGRADED:-false}" = "true" ]; then
@@ -8149,15 +8213,15 @@ except Exception:
8149
8213
  else
8150
8214
  if [ $retry -eq 0 ]; then
8151
8215
  if [ -n "$prd" ]; then
8152
- echo "Loki Mode with PRD at $prd. $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $checklist_status $app_runner_info $playwright_info $memory_context_section $rarv_instruction $memory_instruction $compaction_reminder $completion_instruction $sdlc_instruction $autonomous_suffix"
8216
+ echo "Loki Mode with PRD at $prd. $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $mirofish_context $checklist_status $app_runner_info $playwright_info $memory_context_section $rarv_instruction $memory_instruction $compaction_reminder $completion_instruction $sdlc_instruction $autonomous_suffix"
8153
8217
  else
8154
- echo "Loki Mode. $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $checklist_status $app_runner_info $playwright_info $memory_context_section $analysis_instruction $rarv_instruction $memory_instruction $compaction_reminder $completion_instruction $sdlc_instruction $autonomous_suffix"
8218
+ echo "Loki Mode. $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $mirofish_context $checklist_status $app_runner_info $playwright_info $memory_context_section $analysis_instruction $rarv_instruction $memory_instruction $compaction_reminder $completion_instruction $sdlc_instruction $autonomous_suffix"
8155
8219
  fi
8156
8220
  else
8157
8221
  if [ -n "$prd" ]; then
8158
- echo "Loki Mode - Resume iteration #$iteration (retry #$retry). PRD: $prd. $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $checklist_status $app_runner_info $playwright_info $memory_context_section $rarv_instruction $memory_instruction $compaction_reminder $completion_instruction $sdlc_instruction $autonomous_suffix"
8222
+ echo "Loki Mode - Resume iteration #$iteration (retry #$retry). PRD: $prd. $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $mirofish_context $checklist_status $app_runner_info $playwright_info $memory_context_section $rarv_instruction $memory_instruction $compaction_reminder $completion_instruction $sdlc_instruction $autonomous_suffix"
8159
8223
  else
8160
- echo "Loki Mode - Resume iteration #$iteration (retry #$retry). $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $checklist_status $app_runner_info $playwright_info $memory_context_section Use .loki/generated-prd.md if exists. $rarv_instruction $memory_instruction $compaction_reminder $completion_instruction $sdlc_instruction $autonomous_suffix"
8224
+ echo "Loki Mode - Resume iteration #$iteration (retry #$retry). $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $mirofish_context $checklist_status $app_runner_info $playwright_info $memory_context_section Use .loki/generated-prd.md if exists. $rarv_instruction $memory_instruction $compaction_reminder $completion_instruction $sdlc_instruction $autonomous_suffix"
8161
8225
  fi
8162
8226
  fi
8163
8227
  fi
@@ -8439,6 +8503,97 @@ OPENSPEC_QUEUE_EOF
8439
8503
  log_info "OpenSpec queue population complete"
8440
8504
  }
8441
8505
 
8506
+ #===============================================================================
8507
+ # MiroFish Task Queue Population
8508
+ #===============================================================================
8509
+
8510
+ # Populate the task queue from MiroFish market validation advisory
8511
+ # Only runs once -- skips if queue was already populated from MiroFish
8512
+ populate_mirofish_queue() {
8513
+ # Skip if no MiroFish tasks file
8514
+ if [[ ! -f ".loki/mirofish-tasks.json" ]]; then
8515
+ return 0
8516
+ fi
8517
+
8518
+ # Skip if already populated (marker file)
8519
+ if [[ -f ".loki/queue/.mirofish-populated" ]]; then
8520
+ log_info "MiroFish queue already populated, skipping"
8521
+ return 0
8522
+ fi
8523
+
8524
+ log_step "Populating task queue from MiroFish market validation..."
8525
+
8526
+ # Ensure queue directory exists
8527
+ mkdir -p ".loki/queue"
8528
+
8529
+ # Read MiroFish tasks and create queue entries
8530
+ python3 << 'MIROFISH_QUEUE_EOF'
8531
+ import json
8532
+ import os
8533
+ import sys
8534
+
8535
+ mf_tasks_path = ".loki/mirofish-tasks.json"
8536
+ pending_path = ".loki/queue/pending.json"
8537
+
8538
+ try:
8539
+ with open(mf_tasks_path, "r") as f:
8540
+ mf_tasks = json.load(f)
8541
+ except (json.JSONDecodeError, FileNotFoundError) as e:
8542
+ print(f"Warning: Could not read MiroFish tasks: {e}", file=sys.stderr)
8543
+ sys.exit(0)
8544
+
8545
+ if not isinstance(mf_tasks, list) or not mf_tasks:
8546
+ print("No MiroFish tasks found to queue", file=sys.stderr)
8547
+ sys.exit(0)
8548
+
8549
+ # Load existing pending tasks (if any)
8550
+ existing = []
8551
+ if os.path.exists(pending_path):
8552
+ try:
8553
+ with open(pending_path, "r") as f:
8554
+ data = json.load(f)
8555
+ if isinstance(data, list):
8556
+ existing = data
8557
+ elif isinstance(data, dict) and "tasks" in data:
8558
+ existing = data["tasks"]
8559
+ except (json.JSONDecodeError, FileNotFoundError):
8560
+ existing = []
8561
+
8562
+ # Convert MiroFish tasks to queue format (with deduplication)
8563
+ existing_ids = {t.get("id") for t in existing if isinstance(t, dict)}
8564
+ added = 0
8565
+ for i, task in enumerate(mf_tasks):
8566
+ if not isinstance(task, dict):
8567
+ continue
8568
+ task_id = task.get("id", f"mirofish-{i+1:03d}")
8569
+ if task_id in existing_ids:
8570
+ continue
8571
+ entry = {
8572
+ "id": task_id,
8573
+ "title": task.get("title", f"MiroFish Advisory {i+1}"),
8574
+ "description": task.get("description", ""),
8575
+ "priority": task.get("priority", "medium"),
8576
+ "source": "mirofish",
8577
+ }
8578
+ if task.get("category"):
8579
+ entry["category"] = task["category"]
8580
+ existing.append(entry)
8581
+ added += 1
8582
+
8583
+ with open(pending_path, "w") as f:
8584
+ json.dump(existing, f, indent=2)
8585
+ print(f"Added {added} MiroFish advisory tasks to queue", file=sys.stderr)
8586
+ MIROFISH_QUEUE_EOF
8587
+
8588
+ if [[ $? -ne 0 ]]; then
8589
+ log_warn "Failed to populate MiroFish queue"
8590
+ return 0
8591
+ fi
8592
+
8593
+ touch ".loki/queue/.mirofish-populated"
8594
+ log_info "MiroFish queue population complete"
8595
+ }
8596
+
8442
8597
  #===============================================================================
8443
8598
  # Main Autonomous Loop
8444
8599
  #===============================================================================
@@ -8548,6 +8703,9 @@ run_autonomous() {
8548
8703
  # Populate task queue from OpenSpec artifacts (if present, runs once)
8549
8704
  populate_openspec_queue
8550
8705
 
8706
+ # Populate task queue from MiroFish advisory (if present, runs once)
8707
+ populate_mirofish_queue
8708
+
8551
8709
  # Check max iterations before starting
8552
8710
  if check_max_iterations; then
8553
8711
  log_error "Max iterations already reached. Reset with: rm .loki/autonomy-state.json"
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "6.59.0"
10
+ __version__ = "6.61.0"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -4,10 +4,13 @@ Database setup for Loki Mode Dashboard.
4
4
  Uses SQLAlchemy 2.0 with async support and SQLite.
5
5
  """
6
6
 
7
+ import logging
7
8
  import os
8
9
  from contextlib import asynccontextmanager
9
10
  from typing import AsyncGenerator
10
11
 
12
+ logger = logging.getLogger(__name__)
13
+
11
14
  from sqlalchemy.ext.asyncio import (
12
15
  AsyncSession,
13
16
  async_sessionmaker,
@@ -40,11 +43,14 @@ async_session_factory = async_sessionmaker(
40
43
 
41
44
  async def init_db() -> None:
42
45
  """Initialize the database, creating all tables."""
43
- # Ensure database directory exists
44
46
  os.makedirs(DATABASE_DIR, exist_ok=True)
45
-
46
- async with engine.begin() as conn:
47
- await conn.run_sync(Base.metadata.create_all)
47
+ try:
48
+ async with engine.begin() as conn:
49
+ await conn.run_sync(Base.metadata.create_all)
50
+ logger.info("Database initialized at %s", DATABASE_PATH)
51
+ except Exception as exc:
52
+ logger.error("Database initialization failed: %s", exc, exc_info=True)
53
+ raise
48
54
 
49
55
 
50
56
  async def close_db() -> None:
@@ -52,6 +58,17 @@ async def close_db() -> None:
52
58
  await engine.dispose()
53
59
 
54
60
 
61
+ async def check_db_health() -> bool:
62
+ """Check if the database is accessible."""
63
+ try:
64
+ async with async_session_factory() as session:
65
+ from sqlalchemy import text
66
+ await session.execute(text("SELECT 1"))
67
+ return True
68
+ except Exception:
69
+ return False
70
+
71
+
55
72
  @asynccontextmanager
56
73
  async def get_session() -> AsyncGenerator[AsyncSession, None]:
57
74
  """Get an async database session."""
@@ -30,7 +30,7 @@ from fastapi import (
30
30
  )
31
31
  from fastapi.middleware.cors import CORSMiddleware
32
32
  from fastapi.responses import JSONResponse, PlainTextResponse
33
- from pydantic import BaseModel, Field, field_validator
33
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
34
34
  from sqlalchemy import select, update, delete
35
35
  from sqlalchemy.ext.asyncio import AsyncSession
36
36
  from sqlalchemy.orm import selectinload
@@ -180,6 +180,8 @@ class ProjectUpdate(BaseModel):
180
180
 
181
181
  class ProjectResponse(BaseModel):
182
182
  """Schema for project response."""
183
+ model_config = ConfigDict(from_attributes=True)
184
+
183
185
  id: int
184
186
  name: str
185
187
  description: Optional[str]
@@ -190,9 +192,6 @@ class ProjectResponse(BaseModel):
190
192
  task_count: int = 0
191
193
  completed_task_count: int = 0
192
194
 
193
- class Config:
194
- from_attributes = True
195
-
196
195
 
197
196
  class TaskCreate(BaseModel):
198
197
  """Schema for creating a task."""
@@ -231,6 +230,8 @@ class TaskMove(BaseModel):
231
230
 
232
231
  class TaskResponse(BaseModel):
233
232
  """Schema for task response."""
233
+ model_config = ConfigDict(from_attributes=True)
234
+
234
235
  id: int
235
236
  project_id: int
236
237
  title: str
@@ -246,9 +247,6 @@ class TaskResponse(BaseModel):
246
247
  updated_at: datetime
247
248
  completed_at: Optional[datetime]
248
249
 
249
- class Config:
250
- from_attributes = True
251
-
252
250
 
253
251
  class SessionInfo(BaseModel):
254
252
  """Info about a single running session."""
@@ -416,7 +414,12 @@ async def _push_loki_state_loop() -> None:
416
414
  async def lifespan(app: FastAPI):
417
415
  """Application lifespan handler."""
418
416
  # Startup
419
- await init_db()
417
+ try:
418
+ await init_db()
419
+ app.state.db_available = True
420
+ except Exception as exc:
421
+ logger.error("Database init failed: %s -- DB routes will return 503", exc)
422
+ app.state.db_available = False
420
423
  _telemetry.send_telemetry("dashboard_start")
421
424
  push_task = asyncio.create_task(_push_loki_state_loop())
422
425
  yield
@@ -723,50 +726,54 @@ async def list_projects(
723
726
  db: AsyncSession = Depends(get_db),
724
727
  ) -> list[ProjectResponse]:
725
728
  """List projects with pagination. Does not eager-load tasks for efficiency."""
726
- from sqlalchemy import func as sa_func
727
-
728
- query = select(Project)
729
- if status:
730
- query = query.where(Project.status == status)
731
- query = query.order_by(Project.created_at.desc()).offset(offset).limit(limit)
732
-
733
- result = await db.execute(query)
734
- projects = result.scalars().all()
735
-
736
- # Batch-fetch task counts instead of N+1 eager loading
737
- project_ids = [p.id for p in projects]
738
- response = []
739
- if project_ids:
740
- count_query = (
741
- select(
742
- Task.project_id,
743
- sa_func.count().label("total"),
744
- sa_func.count().filter(Task.status == TaskStatus.DONE).label("done"),
729
+ try:
730
+ from sqlalchemy import func as sa_func
731
+
732
+ query = select(Project)
733
+ if status:
734
+ query = query.where(Project.status == status)
735
+ query = query.order_by(Project.created_at.desc()).offset(offset).limit(limit)
736
+
737
+ result = await db.execute(query)
738
+ projects = result.scalars().all()
739
+
740
+ # Batch-fetch task counts instead of N+1 eager loading
741
+ project_ids = [p.id for p in projects]
742
+ response = []
743
+ if project_ids:
744
+ count_query = (
745
+ select(
746
+ Task.project_id,
747
+ sa_func.count().label("total"),
748
+ sa_func.count().filter(Task.status == TaskStatus.DONE).label("done"),
749
+ )
750
+ .where(Task.project_id.in_(project_ids))
751
+ .group_by(Task.project_id)
745
752
  )
746
- .where(Task.project_id.in_(project_ids))
747
- .group_by(Task.project_id)
748
- )
749
- count_result = await db.execute(count_query)
750
- counts = {row.project_id: (row.total, row.done) for row in count_result}
751
- else:
752
- counts = {}
753
-
754
- for project in projects:
755
- total, done = counts.get(project.id, (0, 0))
756
- response.append(
757
- ProjectResponse(
758
- id=project.id,
759
- name=project.name,
760
- description=project.description,
761
- prd_path=project.prd_path,
762
- status=project.status,
763
- created_at=project.created_at,
764
- updated_at=project.updated_at,
765
- task_count=total,
766
- completed_task_count=done,
753
+ count_result = await db.execute(count_query)
754
+ counts = {row.project_id: (row.total, row.done) for row in count_result}
755
+ else:
756
+ counts = {}
757
+
758
+ for project in projects:
759
+ total, done = counts.get(project.id, (0, 0))
760
+ response.append(
761
+ ProjectResponse(
762
+ id=project.id,
763
+ name=project.name,
764
+ description=project.description,
765
+ prd_path=project.prd_path,
766
+ status=project.status,
767
+ created_at=project.created_at,
768
+ updated_at=project.updated_at,
769
+ task_count=total,
770
+ completed_task_count=done,
771
+ )
767
772
  )
768
- )
769
- return response
773
+ return response
774
+ except Exception as exc:
775
+ logger.error("Failed to list projects: %s", exc, exc_info=True)
776
+ raise HTTPException(status_code=500, detail="Database query failed") from exc
770
777
 
771
778
 
772
779
  @app.post("/api/projects", response_model=ProjectResponse, status_code=201, dependencies=[Depends(auth.require_scope("control"))])
@@ -2133,7 +2140,7 @@ def _get_memory_storage():
2133
2140
  @app.get("/api/memory/search")
2134
2141
  async def search_memory(
2135
2142
  q: str = Query(..., min_length=1, max_length=500, description="Search query"),
2136
- collection: str = Query(default="all", regex="^(episodes|patterns|skills|all)$"),
2143
+ collection: str = Query(default="all", pattern="^(episodes|patterns|skills|all)$"),
2137
2144
  limit: int = Query(default=20, ge=1, le=100),
2138
2145
  ):
2139
2146
  """Full-text search across memory using FTS5."""
@@ -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:** v6.59.0
5
+ **Version:** v6.61.0
6
6
 
7
7
  ---
8
8
 
package/mcp/__init__.py CHANGED
@@ -57,4 +57,4 @@ try:
57
57
  except ImportError:
58
58
  __all__ = ['mcp']
59
59
 
60
- __version__ = '6.59.0'
60
+ __version__ = '6.61.0'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loki-mode",
3
- "version": "6.59.0",
3
+ "version": "6.61.0",
4
4
  "description": "Loki Mode by Autonomi - Multi-agent autonomous startup system for Claude Code, Codex CLI, and Gemini CLI",
5
5
  "keywords": [
6
6
  "agent",
@@ -28,6 +28,7 @@
28
28
  | GitHub issues, PRs, syncing | `github-integration.md` |
29
29
  | Multi-provider (Codex, Gemini) | `providers.md` |
30
30
  | OpenSpec delta context, brownfield modifications | `openspec-integration.md` |
31
+ | MiroFish market validation, `--mirofish` flag | `mirofish-integration.md` |
31
32
  | Plan deepening, knowledge extraction | `compound-learning.md` |
32
33
 
33
34
  ## Module Descriptions
@@ -118,6 +119,13 @@
118
119
  - Source mapping and verification tracking
119
120
  - Complexity-based agent strategy
120
121
 
122
+ ### mirofish-integration.md
123
+ **When:** Project has MiroFish market validation data, `--mirofish` flag used
124
+ - Market validation context interpretation
125
+ - Sentiment-aware feature prioritization
126
+ - Risk-driven task ordering
127
+ - Advisory-only (never gates RARV or Completion Council)
128
+
121
129
  ### compound-learning.md (v5.30.0)
122
130
  **When:** After architecture phase (deepen plan), after verification (extract learnings)
123
131
  - Deepen-plan: 4 parallel research agents enhance plans before implementation
@@ -0,0 +1,100 @@
1
+ # MiroFish Market Validation Integration
2
+
3
+ > MiroFish provides swarm intelligence market validation via simulated user/market
4
+ > reception. Results are **advisory only** and never gate the RARV cycle or
5
+ > Completion Council decisions.
6
+
7
+ ## When This Module Applies
8
+
9
+ Load this module when ANY of the following are true:
10
+ - Your prompt contains a `MIROFISH MARKET VALIDATION` section
11
+ - The project has `.loki/mirofish-context.json`
12
+ - The session was started with `--mirofish` flag
13
+ - Tasks in `.loki/queue/pending.json` have `source: "mirofish"`
14
+
15
+ **If none of the above are true, do not load this module.**
16
+
17
+ ## Understanding MiroFish Advisory Data
18
+
19
+ When present, MiroFish context includes:
20
+ - **overall_sentiment**: positive, negative, or mixed
21
+ - **sentiment_score**: 0.0-1.0 (higher = more positive)
22
+ - **confidence**: low, medium, or high (based on simulation depth)
23
+ - **key_concerns**: Risk items identified by simulated personas
24
+ - **feature_rankings**: Features ranked by simulated reception score
25
+ - **recommendation**: proceed, review_concerns, or reconsider
26
+
27
+ ## Risk-Driven Prioritization
28
+
29
+ When MiroFish identifies key concerns, address them proactively:
30
+
31
+ | Concern Category | Action |
32
+ |-----------------|--------|
33
+ | User adoption / UX | Prioritize UX polish and onboarding |
34
+ | Market fit / demand | Validate core value proposition first |
35
+ | Competition | Differentiate early, focus unique features |
36
+ | Privacy / trust | Add transparency features, opt-in controls |
37
+ | Technical feasibility | Prototype risky components first |
38
+
39
+ ## Sentiment-Aware Feature Ordering
40
+
41
+ Use feature reception scores to influence implementation order:
42
+ - **Score >= 0.8**: High demand -- implement first (validated demand)
43
+ - **Score 0.6-0.79**: Moderate interest -- standard priority
44
+ - **Score 0.4-0.59**: Lukewarm -- consider redesign before building
45
+ - **Score < 0.4**: Low reception -- deprioritize or cut from MVP
46
+
47
+ ## Confidence Score Interpretation
48
+
49
+ | Range | Meaning | Action |
50
+ |-------|---------|--------|
51
+ | 80-100 | Strong market signal | Proceed with confidence |
52
+ | 60-79 | Moderate signal | Consider pivots for weak areas |
53
+ | 40-59 | Weak signal | Recommend PRD revision before heavy implementation |
54
+ | Below 40 | Insufficient data | Treat as noise, proceed with caution |
55
+
56
+ ## Pipeline Status
57
+
58
+ If your prompt contains `MIROFISH_STATUS` instead of full validation data, the
59
+ pipeline is still running. This is normal -- MiroFish simulations take 15-45 minutes.
60
+
61
+ - Continue with implementation using available context
62
+ - Results will appear in subsequent iterations when the pipeline completes
63
+ - Do not wait or block for MiroFish results
64
+
65
+ ## What MiroFish Does NOT Do
66
+
67
+ - Does NOT override Completion Council decisions
68
+ - Does NOT block the RARV cycle
69
+ - Does NOT evaluate code quality (that is the quality gates system)
70
+ - Does NOT make architecture decisions (those are yours)
71
+ - Results are directional signals, not precise measurements
72
+
73
+ ## Known Limitations
74
+
75
+ - **LLM convergence bias**: Simulated agents may converge on similar opinions
76
+ - **Garbage-in-garbage-out**: Poor PRD = poor simulation seed = unreliable results
77
+ - **No real user data**: Synthetic personas, not actual market research
78
+ - **Cultural bias**: Agent behavior reflects LLM training data distributions
79
+ - **Timing**: Results arrive 15-45 min after launch, may miss early iterations
80
+
81
+ ## Configuration
82
+
83
+ MiroFish requires these environment variables for its Docker container:
84
+ - `LLM_API_KEY` (required) -- API key for MiroFish's LLM provider
85
+ - `ZEP_API_KEY` (required) -- Zep Cloud key for graph memory
86
+
87
+ CLI flags:
88
+ - `--mirofish [URL]` -- Enable with optional custom URL (default: localhost:5001)
89
+ - `--mirofish-docker IMAGE` -- Auto-start MiroFish Docker container
90
+ - `--mirofish-rounds N` -- Simulation rounds (default: 100)
91
+ - `--mirofish-timeout S` -- Max pipeline wait (default: 3600s)
92
+ - `--mirofish-bg` -- Run in background mode
93
+ - `--no-mirofish` -- Disable even if LOKI_MIROFISH_URL is set
94
+
95
+ ## MiroFish Task Queue
96
+
97
+ When MiroFish completes, actionable items from the report are added to the task
98
+ queue with `source: "mirofish"`. These tasks represent risk mitigations and
99
+ recommendations. They are advisory -- prioritize alongside normal development tasks
100
+ based on the concern severity and your judgment.