ifcraftcorpus 1.2.1__py3-none-any.whl → 1.3.0__py3-none-any.whl

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.
Files changed (60) hide show
  1. ifcraftcorpus/cli.py +21 -5
  2. ifcraftcorpus/mcp_server.py +38 -12
  3. ifcraftcorpus/providers.py +48 -10
  4. {ifcraftcorpus-1.2.1.dist-info → ifcraftcorpus-1.3.0.dist-info}/METADATA +1 -1
  5. {ifcraftcorpus-1.2.1.dist-info → ifcraftcorpus-1.3.0.dist-info}/RECORD +60 -60
  6. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/agent-design/agent_prompt_engineering.md +0 -0
  7. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/agent-design/multi_agent_patterns.md +0 -0
  8. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/audience-and-access/accessibility_guidelines.md +0 -0
  9. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/audience-and-access/audience_targeting.md +0 -0
  10. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/audience-and-access/localization_considerations.md +0 -0
  11. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/craft-foundations/audio_visual_integration.md +0 -0
  12. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/craft-foundations/collaborative_if_writing.md +0 -0
  13. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/craft-foundations/creative_workflow_pipeline.md +0 -0
  14. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/craft-foundations/diegetic_design.md +0 -0
  15. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/craft-foundations/idea_capture_and_hooks.md +0 -0
  16. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/craft-foundations/if_platform_tools.md +0 -0
  17. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/craft-foundations/player_analytics_metrics.md +0 -0
  18. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/craft-foundations/quality_standards_if.md +0 -0
  19. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/craft-foundations/research_and_verification.md +0 -0
  20. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/craft-foundations/testing_interactive_fiction.md +0 -0
  21. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/emotional-design/conflict_patterns.md +0 -0
  22. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/emotional-design/emotional_beats.md +0 -0
  23. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/game-design/mechanics_design_patterns.md +0 -0
  24. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/genre-conventions/children_and_ya_conventions.md +0 -0
  25. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/genre-conventions/fantasy_conventions.md +0 -0
  26. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/genre-conventions/historical_fiction.md +0 -0
  27. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/genre-conventions/horror_conventions.md +0 -0
  28. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/genre-conventions/mystery_conventions.md +0 -0
  29. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/genre-conventions/sci_fi_conventions.md +0 -0
  30. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/narrative-structure/branching_narrative_construction.md +0 -0
  31. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/narrative-structure/branching_narrative_craft.md +0 -0
  32. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/narrative-structure/endings_patterns.md +0 -0
  33. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/narrative-structure/episodic_serialized_if.md +0 -0
  34. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/narrative-structure/nonlinear_structure.md +0 -0
  35. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/narrative-structure/pacing_and_tension.md +0 -0
  36. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/narrative-structure/romance_and_relationships.md +0 -0
  37. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/narrative-structure/scene_structure_and_beats.md +0 -0
  38. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/narrative-structure/scene_transitions.md +0 -0
  39. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/prose-and-language/character_voice.md +0 -0
  40. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/prose-and-language/dialogue_craft.md +0 -0
  41. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/prose-and-language/exposition_techniques.md +0 -0
  42. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/prose-and-language/narrative_point_of_view.md +0 -0
  43. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/prose-and-language/prose_patterns.md +0 -0
  44. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/prose-and-language/subtext_and_implication.md +0 -0
  45. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/prose-and-language/voice_register_consistency.md +0 -0
  46. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/scope-and-planning/scope_and_length.md +0 -0
  47. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/world-and-setting/canon_management.md +0 -0
  48. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/world-and-setting/setting_as_character.md +0 -0
  49. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/corpus/world-and-setting/worldbuilding_patterns.md +0 -0
  50. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/subagents/README.md +0 -0
  51. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/subagents/if_genre_consultant.md +0 -0
  52. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/subagents/if_platform_advisor.md +0 -0
  53. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/subagents/if_prose_writer.md +0 -0
  54. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/subagents/if_quality_reviewer.md +0 -0
  55. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/subagents/if_story_architect.md +0 -0
  56. {ifcraftcorpus-1.2.1.data → ifcraftcorpus-1.3.0.data}/data/share/ifcraftcorpus/subagents/if_world_curator.md +0 -0
  57. {ifcraftcorpus-1.2.1.dist-info → ifcraftcorpus-1.3.0.dist-info}/WHEEL +0 -0
  58. {ifcraftcorpus-1.2.1.dist-info → ifcraftcorpus-1.3.0.dist-info}/entry_points.txt +0 -0
  59. {ifcraftcorpus-1.2.1.dist-info → ifcraftcorpus-1.3.0.dist-info}/licenses/LICENSE +0 -0
  60. {ifcraftcorpus-1.2.1.dist-info → ifcraftcorpus-1.3.0.dist-info}/licenses/LICENSE-CONTENT +0 -0
ifcraftcorpus/cli.py CHANGED
@@ -125,7 +125,10 @@ def cmd_embeddings_status(args: argparse.Namespace) -> int:
125
125
  status = "✓ Available" if available else "✗ Not available"
126
126
  print(f"{name:20} {status}")
127
127
  if available:
128
- print(f"{'':20} Model: {provider.model} ({provider.dimension}d)")
128
+ extra_info = ""
129
+ if hasattr(provider, "cpu_only") and provider.cpu_only:
130
+ extra_info = " [CPU-only]"
131
+ print(f"{'':20} Model: {provider.model} ({provider.dimension}d){extra_info}")
129
132
 
130
133
  # Auto-detect
131
134
  print("\n=== Auto-Detection ===\n")
@@ -164,9 +167,10 @@ def cmd_embeddings_build(args: argparse.Namespace) -> int:
164
167
 
165
168
  # Get provider
166
169
  provider: EmbeddingProvider | None = None
170
+ cpu_only = getattr(args, "cpu_only", False)
167
171
  if args.provider:
168
172
  if args.provider == "ollama":
169
- provider = OllamaEmbeddings(model=args.model, host=args.ollama_host)
173
+ provider = OllamaEmbeddings(model=args.model, host=args.ollama_host, cpu_only=cpu_only)
170
174
  elif args.provider == "openai":
171
175
  provider = OpenAIEmbeddings(model=args.model, api_key=args.openai_key)
172
176
  elif args.provider in ("sentence-transformers", "st", "local"):
@@ -175,7 +179,7 @@ def cmd_embeddings_build(args: argparse.Namespace) -> int:
175
179
  print(f"Unknown provider: {args.provider}", file=sys.stderr)
176
180
  return 1
177
181
  else:
178
- provider = get_embedding_provider(model=args.model)
182
+ provider = get_embedding_provider(model=args.model, cpu_only=cpu_only)
179
183
 
180
184
  if not provider:
181
185
  print("No embedding provider available.", file=sys.stderr)
@@ -186,13 +190,19 @@ def cmd_embeddings_build(args: argparse.Namespace) -> int:
186
190
  print(f"Provider {provider.provider_name} is not available.", file=sys.stderr)
187
191
  return 1
188
192
 
193
+ # Show CPU-only status for Ollama
194
+ cpu_only_status = ""
195
+ if hasattr(provider, "cpu_only") and provider.cpu_only:
196
+ cpu_only_status = " (CPU-only)"
197
+
189
198
  logger.info(
190
- "CLI embeddings build provider=%s model=%s output=%s",
199
+ "CLI embeddings build provider=%s model=%s output=%s cpu_only=%s",
191
200
  provider.provider_name,
192
201
  provider.model,
193
202
  args.output,
203
+ getattr(provider, "cpu_only", False),
194
204
  )
195
- print(f"Using provider: {provider.provider_name}")
205
+ print(f"Using provider: {provider.provider_name}{cpu_only_status}")
196
206
  print(f"Model: {provider.model} ({provider.dimension}d)")
197
207
 
198
208
  # Build embeddings
@@ -308,6 +318,12 @@ def main() -> int:
308
318
  )
309
319
  emb_build.add_argument("--ollama-host", help="Ollama host URL")
310
320
  emb_build.add_argument("--openai-key", help="OpenAI API key")
321
+ emb_build.add_argument(
322
+ "--cpu-only",
323
+ action="store_true",
324
+ help="Force CPU-only inference for Ollama (num_gpu=0). "
325
+ "Useful when GPU is under VRAM pressure.",
326
+ )
311
327
  emb_build.set_defaults(func=cmd_embeddings_build)
312
328
 
313
329
  args = parser.parse_args()
@@ -367,11 +367,15 @@ def embeddings_status() -> dict[str, Any]:
367
367
  try:
368
368
  provider = cls()
369
369
  available = provider.check_availability()
370
- result["providers"][name] = {
370
+ provider_info: dict[str, Any] = {
371
371
  "available": available,
372
372
  "model": provider.model if available else None,
373
373
  "dimension": provider.dimension if available else None,
374
374
  }
375
+ # Add cpu_only info for Ollama
376
+ if hasattr(provider, "cpu_only"):
377
+ provider_info["cpu_only"] = provider.cpu_only
378
+ result["providers"][name] = provider_info
375
379
  except Exception as exc: # pragma: no cover - defensive logging
376
380
  logger.warning("Failed to inspect embedding provider %s: %s", name, exc)
377
381
  result["providers"][name] = {"available": False, "error": "import_failed"}
@@ -409,6 +413,8 @@ def embeddings_status() -> dict[str, Any]:
409
413
  @tool
410
414
  def build_embeddings(
411
415
  provider: str | None = None,
416
+ model: str | None = None,
417
+ cpu_only: bool | None = None,
412
418
  force: bool = False,
413
419
  ) -> dict[str, Any]:
414
420
  """Build or rebuild the embedding index for semantic search.
@@ -420,6 +426,11 @@ def build_embeddings(
420
426
  provider: Embedding provider to use: "ollama", "openai", or
421
427
  "sentence_transformers". If None, auto-detects the best
422
428
  available provider.
429
+ model: Embedding model name override. If None, uses provider default
430
+ or OLLAMA_MODEL env var for Ollama.
431
+ cpu_only: For Ollama provider, force CPU-only inference (num_gpu=0).
432
+ Useful when GPU is under VRAM pressure. If None, reads from
433
+ OLLAMA_CPU_ONLY env var.
423
434
  force: If True, rebuild even if embeddings already exist.
424
435
 
425
436
  Returns:
@@ -427,15 +438,23 @@ def build_embeddings(
427
438
 
428
439
  Note:
429
440
  Ollama requires a running Ollama server (configure with OLLAMA_HOST env).
441
+ Set OLLAMA_CPU_ONLY=true to force CPU inference.
430
442
  OpenAI requires OPENAI_API_KEY environment variable.
431
443
  SentenceTransformers requires the sentence-transformers package.
432
444
  """
433
445
  global _corpus
434
446
 
435
- logger.info("build_embeddings requested provider=%s force=%s", provider, force)
447
+ logger.info(
448
+ "build_embeddings requested provider=%s model=%s cpu_only=%s force=%s",
449
+ provider,
450
+ model,
451
+ cpu_only,
452
+ force,
453
+ )
436
454
 
437
455
  try:
438
456
  from ifcraftcorpus.providers import (
457
+ EmbeddingProvider,
439
458
  OllamaEmbeddings,
440
459
  OpenAIEmbeddings,
441
460
  SentenceTransformersEmbeddings,
@@ -449,21 +468,22 @@ def build_embeddings(
449
468
  }
450
469
 
451
470
  # Get provider
452
- embedding_provider = None
471
+ embedding_provider: EmbeddingProvider | None = None
453
472
  if provider:
454
- provider_map = {
455
- "ollama": OllamaEmbeddings,
456
- "openai": OpenAIEmbeddings,
457
- "sentence_transformers": SentenceTransformersEmbeddings,
458
- }
459
- if provider not in provider_map:
473
+ provider_lower = provider.lower()
474
+ if provider_lower == "ollama":
475
+ embedding_provider = OllamaEmbeddings(model=model, cpu_only=cpu_only)
476
+ elif provider_lower == "openai":
477
+ embedding_provider = OpenAIEmbeddings(model=model)
478
+ elif provider_lower == "sentence_transformers":
479
+ embedding_provider = SentenceTransformersEmbeddings(model=model)
480
+ else:
460
481
  logger.warning("Unknown embeddings provider requested: %s", provider)
461
482
  return {
462
483
  "error": f"Unknown provider: {provider}. Use: ollama, openai, sentence_transformers"
463
484
  }
464
- embedding_provider = provider_map[provider]()
465
485
  else:
466
- embedding_provider = get_embedding_provider()
486
+ embedding_provider = get_embedding_provider(model=model, cpu_only=cpu_only)
467
487
 
468
488
  if not embedding_provider:
469
489
  logger.warning("No embedding provider available for build request")
@@ -506,7 +526,7 @@ def build_embeddings(
506
526
  # Update global corpus to use new embeddings
507
527
  _corpus = Corpus(embeddings_path=embeddings_path)
508
528
 
509
- return {
529
+ result = {
510
530
  "status": "success",
511
531
  "items_embedded": count,
512
532
  "provider": embedding_provider.provider_name,
@@ -514,6 +534,12 @@ def build_embeddings(
514
534
  "path": str(embeddings_path),
515
535
  }
516
536
 
537
+ # Add cpu_only info for Ollama
538
+ if hasattr(embedding_provider, "cpu_only"):
539
+ result["cpu_only"] = embedding_provider.cpu_only
540
+
541
+ return result
542
+
517
543
 
518
544
  # =============================================================================
519
545
  # Subagent Prompts
@@ -9,7 +9,12 @@ Supports multiple backends:
9
9
  Provider selection via environment:
10
10
  - EMBEDDING_PROVIDER: "ollama", "openai", or "sentence-transformers"
11
11
  - OLLAMA_HOST: Ollama server URL (default: http://localhost:11434)
12
+ - IFCRAFTCORPUS_OLLAMA_MODEL: Ollama embedding model (default: nomic-embed-text)
13
+ - IFCRAFTCORPUS_OLLAMA_CPU_ONLY: Set to "true" or "1" to force CPU-only inference
12
14
  - OPENAI_API_KEY: OpenAI API key (required for openai provider)
15
+
16
+ Note: The IFCRAFTCORPUS_ prefix avoids conflicts with other applications
17
+ that may use Ollama with different model/GPU configurations.
13
18
  """
14
19
 
15
20
  from __future__ import annotations
@@ -113,24 +118,44 @@ class OllamaEmbeddings(EmbeddingProvider):
113
118
  Recommended model: nomic-embed-text (768 dimensions)
114
119
 
115
120
  Requires: httpx (pip install httpx)
121
+
122
+ Environment variables:
123
+ OLLAMA_HOST: Server URL (default: http://localhost:11434)
124
+ IFCRAFTCORPUS_OLLAMA_MODEL: Model name (default: nomic-embed-text)
125
+ IFCRAFTCORPUS_OLLAMA_CPU_ONLY: Set to "true" or "1" to force CPU-only inference
126
+
127
+ Note: The IFCRAFTCORPUS_ prefix avoids conflicts with other applications
128
+ that may use Ollama with different model/GPU configurations.
116
129
  """
117
130
 
118
131
  def __init__(
119
132
  self,
120
133
  model: str | None = None,
121
134
  host: str | None = None,
135
+ cpu_only: bool | None = None,
122
136
  ):
123
137
  """
124
138
  Initialize Ollama embeddings.
125
139
 
126
140
  Args:
127
- model: Embedding model name (default: nomic-embed-text)
128
- host: Ollama host URL (default: http://localhost:11434)
141
+ model: Embedding model name (default: nomic-embed-text, or
142
+ IFCRAFTCORPUS_OLLAMA_MODEL env)
143
+ host: Ollama host URL (default: http://localhost:11434, or OLLAMA_HOST env)
144
+ cpu_only: Force CPU-only inference with num_gpu=0 (default: False, or
145
+ IFCRAFTCORPUS_OLLAMA_CPU_ONLY env). Useful when GPU is under
146
+ VRAM pressure or to avoid contention with other GPU workloads.
129
147
  """
130
- self._model = model or DEFAULT_MODELS["ollama"]
148
+ self._model = model or os.getenv("IFCRAFTCORPUS_OLLAMA_MODEL") or DEFAULT_MODELS["ollama"]
131
149
  self._host = host or os.getenv("OLLAMA_HOST", "http://localhost:11434")
132
150
  self._dimension = MODEL_DIMENSIONS.get(self._model, 768)
133
151
 
152
+ # CPU-only mode: check parameter, then env var
153
+ if cpu_only is not None:
154
+ self._cpu_only = cpu_only
155
+ else:
156
+ env_val = os.getenv("IFCRAFTCORPUS_OLLAMA_CPU_ONLY", "").lower()
157
+ self._cpu_only = env_val in ("true", "1", "yes")
158
+
134
159
  @property
135
160
  def model(self) -> str:
136
161
  return self._model
@@ -143,20 +168,30 @@ class OllamaEmbeddings(EmbeddingProvider):
143
168
  def provider_name(self) -> str:
144
169
  return "ollama"
145
170
 
171
+ @property
172
+ def cpu_only(self) -> bool:
173
+ """Whether CPU-only mode is enabled."""
174
+ return self._cpu_only
175
+
146
176
  def embed(self, texts: list[str]) -> EmbeddingResult:
147
177
  """Embed texts using Ollama."""
148
178
  import httpx
149
179
 
150
180
  embeddings: list[list[float]] = []
151
181
 
182
+ # Build request payload
183
+ base_payload: dict[str, object] = {"model": self._model}
184
+
185
+ # Add options for CPU-only mode
186
+ if self._cpu_only:
187
+ base_payload["options"] = {"num_gpu": 0}
188
+
152
189
  with httpx.Client(timeout=60.0) as client:
153
190
  for text in texts:
191
+ payload = {**base_payload, "prompt": text}
154
192
  response = client.post(
155
193
  f"{self._host}/api/embeddings",
156
- json={
157
- "model": self._model,
158
- "prompt": text,
159
- },
194
+ json=payload,
160
195
  )
161
196
  response.raise_for_status()
162
197
  data = response.json()
@@ -372,6 +407,7 @@ class SentenceTransformersEmbeddings(EmbeddingProvider):
372
407
  def get_embedding_provider(
373
408
  provider_name: str | None = None,
374
409
  model: str | None = None,
410
+ cpu_only: bool | None = None,
375
411
  ) -> EmbeddingProvider | None:
376
412
  """
377
413
  Get an embedding provider based on configuration.
@@ -384,6 +420,8 @@ def get_embedding_provider(
384
420
  Args:
385
421
  provider_name: Explicit provider name ("ollama", "openai", "sentence-transformers")
386
422
  model: Optional model override
423
+ cpu_only: For Ollama, force CPU-only inference (num_gpu=0). If None, reads
424
+ from OLLAMA_CPU_ONLY env var.
387
425
 
388
426
  Returns:
389
427
  Configured EmbeddingProvider or None if none available
@@ -395,7 +433,7 @@ def get_embedding_provider(
395
433
  name = name.lower()
396
434
  provider: EmbeddingProvider
397
435
  if name == "ollama":
398
- provider = OllamaEmbeddings(model=model)
436
+ provider = OllamaEmbeddings(model=model, cpu_only=cpu_only)
399
437
  elif name == "openai":
400
438
  provider = OpenAIEmbeddings(model=model)
401
439
  elif name in ("sentence-transformers", "st", "local"):
@@ -410,9 +448,9 @@ def get_embedding_provider(
410
448
  return None
411
449
 
412
450
  # Auto-detect: try Ollama first, then OpenAI, then SentenceTransformers
413
- ollama = OllamaEmbeddings(model=model)
451
+ ollama = OllamaEmbeddings(model=model, cpu_only=cpu_only)
414
452
  if ollama.check_availability():
415
- logger.info(f"Using Ollama embeddings ({ollama.model})")
453
+ logger.info(f"Using Ollama embeddings ({ollama.model}, cpu_only={ollama.cpu_only})")
416
454
  return ollama
417
455
 
418
456
  openai = OpenAIEmbeddings(model=model)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ifcraftcorpus
3
- Version: 1.2.1
3
+ Version: 1.3.0
4
4
  Summary: Interactive fiction craft corpus with search library and MCP server
5
5
  Project-URL: Homepage, https://pvliesdonk.github.io/if-craft-corpus
6
6
  Project-URL: Repository, https://github.com/pvliesdonk/if-craft-corpus
@@ -1,67 +1,67 @@
1
1
  ifcraftcorpus/__init__.py,sha256=sZlp_jM2CGbkQ6R3te-wXH9IkZ7Zp585fj1MMq21WUQ,2087
2
- ifcraftcorpus/cli.py,sha256=ZY6T7kj66S1cfeJ75r7VoNkXCtnfcxCcUpA3bRQUi8k,10454
2
+ ifcraftcorpus/cli.py,sha256=aTLZCuSTZ9884nxvngj2RX1VHl9PXKVMMeYAQIVMU6I,11131
3
3
  ifcraftcorpus/embeddings.py,sha256=ChRqB1HSCAImczARQQ0Vg_xS5fMPnvd2cg2tFzVaSDc,12962
4
4
  ifcraftcorpus/index.py,sha256=mRCN5r7VnwXxc8e1rfBsUDpxnhQFqKvvDcHcHeEXy_I,19262
5
5
  ifcraftcorpus/logging_utils.py,sha256=_0c4Y_caKObVRsfgeoi5l5ZvSx0JY_xZDnWa85sBUu0,2179
6
- ifcraftcorpus/mcp_server.py,sha256=qs8_ShSyWQsP4e17xbyr2ZlaDly9yDzcXtger-AZvmc,26401
6
+ ifcraftcorpus/mcp_server.py,sha256=jm3w_uqeyDpd5D3iB7ZxNJU7dxQnIXmWO7gvgemaeBk,27539
7
7
  ifcraftcorpus/parser.py,sha256=M6iKnj0_bqA8tgl7tg1SLYzlOItS_Bs2M1RTwqTTFbw,10859
8
- ifcraftcorpus/providers.py,sha256=IvKVRbxYLLM3siOAu8X8nOsL1xHmp37Xuryi1MggBj4,12597
8
+ ifcraftcorpus/providers.py,sha256=1cuaB72-fVyt2J441AR7lfn6HuHtM33G6mPZYdYREN0,14508
9
9
  ifcraftcorpus/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  ifcraftcorpus/search.py,sha256=hz81U44qXb-ZLbAcgDKsj4H_9t1ESxorRWsGSiuHu2I,20962
11
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/agent-design/agent_prompt_engineering.md,sha256=y-AO3w6MdoSQNV7zHQtJrjJSWM9a6LCSlunXyWWbTjQ,26134
12
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/agent-design/multi_agent_patterns.md,sha256=Npnx5qxYOQfbiPGgbeZOfyWKr4ImcCTUhOJcgJYH1HY,13275
13
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/audience-and-access/accessibility_guidelines.md,sha256=SN8tORkgdYYSIcKNQBV-ju8eL2M7Lij9UEZ3AvuUQbY,9892
14
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/audience-and-access/audience_targeting.md,sha256=ESZ4fyiCgtWVXXrXZIViCNU0ohIFdNcC8CU9dkRfPSQ,11037
15
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/audience-and-access/localization_considerations.md,sha256=Mgn2bVN_ugFhsZjRomOstayylzFtrzza-lw-T2p3Lnw,9787
16
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/craft-foundations/audio_visual_integration.md,sha256=YE6pdZr7FNe9VIodgF0xttmzSjfZf0guQ81N3Rbkui4,9892
17
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/craft-foundations/collaborative_if_writing.md,sha256=inDHVyqP3zdP-WBWueeKvDb9Ulqu55AUK61lbhIC82w,9929
18
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/craft-foundations/creative_workflow_pipeline.md,sha256=N5ieILKrKB06hrlegFX-5iOvpXQO8sT5MERiFxxRGZY,10305
19
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/craft-foundations/diegetic_design.md,sha256=FsLT2o3D8znEZrHRzg0L_z0sbg58yTzUk8O70FtGGcE,9183
20
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/craft-foundations/idea_capture_and_hooks.md,sha256=wcidi47Elg38Y-1fuVEW6xn68rL_NqPR5x1IcsPu6ZI,8734
21
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/craft-foundations/if_platform_tools.md,sha256=1Kh_xYjy654RkDxVAw5Ji3pgOKRc1WNdxNu93v9Af3Y,11172
22
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/craft-foundations/player_analytics_metrics.md,sha256=sUuPYmmLn5LMLUd9E-ExhauqF101vcqh51NYc99yyv8,9064
23
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/craft-foundations/quality_standards_if.md,sha256=gS6Jr7OWZKmRvtrSrrCkuM8CgqgLCZ1XAHYBSnbEYH8,16432
24
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/craft-foundations/research_and_verification.md,sha256=WFYaq3boUlHueXWkZygxO9s9astK5aMOaVPE6u-CCeI,9874
25
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/craft-foundations/testing_interactive_fiction.md,sha256=McnbMEgm_PbaxT-dUu8rTzkOOLkIjECKlxVFzcyr7rc,10504
26
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/emotional-design/conflict_patterns.md,sha256=hPV78jR8W4rYiW52m4n_Ifn3nMGDW7tPEPik4kekiIE,12056
27
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/emotional-design/emotional_beats.md,sha256=1yblsg1NLT8CW3qfnQX7WXNflnQhyKYc-_9nb1zgWs4,10229
28
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/game-design/mechanics_design_patterns.md,sha256=sbBWhX8BQOIMyrYfdBjpjlhLeqE_vOuGQXXGFn-zY0U,4506
29
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/genre-conventions/children_and_ya_conventions.md,sha256=b5juJi2z3FMYKL5Tkw08E1jjtlvQdMy3sbDoU0PV88w,3680
30
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/genre-conventions/fantasy_conventions.md,sha256=AN-Mc9kkZKOE4qr8jwAyt6Yh5WlXqRFTPad0BS9joY0,13925
31
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/genre-conventions/historical_fiction.md,sha256=6mAgLSfAD2EV-UCE5WJM1Wk4ARsCuYofKR3Dn0Kcfhg,12016
32
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/genre-conventions/horror_conventions.md,sha256=449Ik17haBHnlIfGkh6FwDqoes8K-y7WKNimGxSq5yg,12883
33
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/genre-conventions/mystery_conventions.md,sha256=xZLCcO3MZJ4dghzoMbITZUc1A7xGpSL1B9LtR74Fhj4,12282
34
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/genre-conventions/sci_fi_conventions.md,sha256=dNkeIipLgtui2Xt6kPlEHT0HHNnCbPDFBQyH_5-1RfQ,5636
35
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/narrative-structure/branching_narrative_construction.md,sha256=Rv8t7zn4g3K6mF1NaHYXAX_vEAdUFcfa-aDA44bAOqs,22265
36
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/narrative-structure/branching_narrative_craft.md,sha256=I4APmDwCQ9dVF9blORxgF_YArfj9aSrTP8TpXJYI-jA,10906
37
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/narrative-structure/endings_patterns.md,sha256=RyxJfZuFyuyEKzmR32H9kBs4jUbeahwylNLkp2oiEjg,10581
38
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/narrative-structure/episodic_serialized_if.md,sha256=tEGRl-L3gRTXmbfoQZ-fCS2CR9xr-dHQgaQNcI4hHdA,9337
39
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/narrative-structure/nonlinear_structure.md,sha256=PfomsB5-l7DwGr1udbvgsTNdJaCdXgLhdYDvBUyKq2k,6287
40
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/narrative-structure/pacing_and_tension.md,sha256=0jlbJwzK2wNLxFQO4zHu6a53vM1Kwb6f5simamexKBU,9530
41
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/narrative-structure/romance_and_relationships.md,sha256=OW3nO9Qn_lCFWRGNyTKQMEOHnmuAA9rIo7wORaF_73U,4012
42
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/narrative-structure/scene_structure_and_beats.md,sha256=WL7buciBLTcl0vyTsLZcEgMI0U6ikA2t0EY9QkKpkJk,10094
43
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/narrative-structure/scene_transitions.md,sha256=Vu33QmpqWRnja4ITvcJepZ2f1NxK6fdwlroJUsczc1c,8500
44
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/prose-and-language/character_voice.md,sha256=gFQptHphCu9pZ2MzqaCVHvpSiHCefi4vBrwZtsfN0R8,11409
45
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/prose-and-language/dialogue_craft.md,sha256=4aQed24AQ7-VdYiaxjQ0JlK13qeNe3Gq1QgJiAqNEG4,11591
46
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/prose-and-language/exposition_techniques.md,sha256=T06IupDgh7MHQDkhHzo5U0ewDqGs5D60nGFn1V2NV-A,10023
47
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/prose-and-language/narrative_point_of_view.md,sha256=G_mZUPh4qxe3LdzO6hiFizJqbh4QKq6ukjcgTyeKPQ8,11020
48
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/prose-and-language/prose_patterns.md,sha256=UFEancpG4_TG3M7KnJGkZCvkafP6TxkhXEKEZgFPWug,10146
49
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/prose-and-language/subtext_and_implication.md,sha256=jKwBTZx5gVy84AG6x2hHmPwbFIiti419-DaDO4oXlH8,10726
50
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/prose-and-language/voice_register_consistency.md,sha256=JtY5bwIrrY1Cjy2ITGOGxCepDhoQnr7nzt2pqr2SKtI,9701
51
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/scope-and-planning/scope_and_length.md,sha256=fF6TDuLSJv5Uf7ov9_Eq0beh8OQF4RBEDmekjZbHkJQ,10315
52
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/world-and-setting/canon_management.md,sha256=ab1XjWXv3RzEWaChfUJOOSnRKjuQsUDaqYQ3T9bw9o0,10576
53
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/world-and-setting/setting_as_character.md,sha256=F0kM5EKlDldqPg2UyyfKx05fRyaWIoE-A-sIhl461Cw,9650
54
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/corpus/world-and-setting/worldbuilding_patterns.md,sha256=IpvZkT6sV3yC23RsICxpeMgb_FT_1mkv1z4NiHKNEIY,11905
55
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/subagents/README.md,sha256=FI9SqJfOg8hoO-3S_dpeIfepPRcd0fyquM7f5Y1J5eE,5817
56
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/subagents/if_genre_consultant.md,sha256=QshDQK4HkMNXYigU91r0CTosl5a-lKqvO9tQMFkbUFI,7244
57
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/subagents/if_platform_advisor.md,sha256=e_uV0vt5Nqah6bUNsiWVhmSuQeF0RIWAZOXJNygpeW8,8515
58
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/subagents/if_prose_writer.md,sha256=fjOazUCXvW62xrhZAsv7ynaDSpG_f1gGK2NJ0clJ1EQ,5927
59
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/subagents/if_quality_reviewer.md,sha256=PLPJtf-6t-jugN75k7EG7ln7S47TT0FcVjWVsRLGOz8,6992
60
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/subagents/if_story_architect.md,sha256=rF_U0Nd3tK0HzaLK6wGL36hRb0B6dfuc6lljAU9pmmo,4936
61
- ifcraftcorpus-1.2.1.data/data/share/ifcraftcorpus/subagents/if_world_curator.md,sha256=xmbGF--5te8uxfimKFw45bFrhbdRM3LPaYBlhUd4swc,7376
62
- ifcraftcorpus-1.2.1.dist-info/METADATA,sha256=H9JUOQkXgqYtqwmYxpFzQXpl6VAo_VyzJbiaN2bNkIQ,4989
63
- ifcraftcorpus-1.2.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
64
- ifcraftcorpus-1.2.1.dist-info/entry_points.txt,sha256=E8DYJ_qWOgPe758ULKth3gcYo-1XkNEvDomhFjJ-B-U,110
65
- ifcraftcorpus-1.2.1.dist-info/licenses/LICENSE,sha256=7MoRwpgeEClx14esn2SJnOLz4jvxWP1uN_vjnC2XTHQ,1067
66
- ifcraftcorpus-1.2.1.dist-info/licenses/LICENSE-CONTENT,sha256=jhGwmahhy9rUFJSSrLUrssnrfa-mXotvNEwq74i93x8,639
67
- ifcraftcorpus-1.2.1.dist-info/RECORD,,
11
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/agent-design/agent_prompt_engineering.md,sha256=y-AO3w6MdoSQNV7zHQtJrjJSWM9a6LCSlunXyWWbTjQ,26134
12
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/agent-design/multi_agent_patterns.md,sha256=Npnx5qxYOQfbiPGgbeZOfyWKr4ImcCTUhOJcgJYH1HY,13275
13
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/audience-and-access/accessibility_guidelines.md,sha256=SN8tORkgdYYSIcKNQBV-ju8eL2M7Lij9UEZ3AvuUQbY,9892
14
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/audience-and-access/audience_targeting.md,sha256=ESZ4fyiCgtWVXXrXZIViCNU0ohIFdNcC8CU9dkRfPSQ,11037
15
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/audience-and-access/localization_considerations.md,sha256=Mgn2bVN_ugFhsZjRomOstayylzFtrzza-lw-T2p3Lnw,9787
16
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/craft-foundations/audio_visual_integration.md,sha256=YE6pdZr7FNe9VIodgF0xttmzSjfZf0guQ81N3Rbkui4,9892
17
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/craft-foundations/collaborative_if_writing.md,sha256=inDHVyqP3zdP-WBWueeKvDb9Ulqu55AUK61lbhIC82w,9929
18
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/craft-foundations/creative_workflow_pipeline.md,sha256=N5ieILKrKB06hrlegFX-5iOvpXQO8sT5MERiFxxRGZY,10305
19
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/craft-foundations/diegetic_design.md,sha256=FsLT2o3D8znEZrHRzg0L_z0sbg58yTzUk8O70FtGGcE,9183
20
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/craft-foundations/idea_capture_and_hooks.md,sha256=wcidi47Elg38Y-1fuVEW6xn68rL_NqPR5x1IcsPu6ZI,8734
21
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/craft-foundations/if_platform_tools.md,sha256=1Kh_xYjy654RkDxVAw5Ji3pgOKRc1WNdxNu93v9Af3Y,11172
22
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/craft-foundations/player_analytics_metrics.md,sha256=sUuPYmmLn5LMLUd9E-ExhauqF101vcqh51NYc99yyv8,9064
23
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/craft-foundations/quality_standards_if.md,sha256=gS6Jr7OWZKmRvtrSrrCkuM8CgqgLCZ1XAHYBSnbEYH8,16432
24
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/craft-foundations/research_and_verification.md,sha256=WFYaq3boUlHueXWkZygxO9s9astK5aMOaVPE6u-CCeI,9874
25
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/craft-foundations/testing_interactive_fiction.md,sha256=McnbMEgm_PbaxT-dUu8rTzkOOLkIjECKlxVFzcyr7rc,10504
26
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/emotional-design/conflict_patterns.md,sha256=hPV78jR8W4rYiW52m4n_Ifn3nMGDW7tPEPik4kekiIE,12056
27
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/emotional-design/emotional_beats.md,sha256=1yblsg1NLT8CW3qfnQX7WXNflnQhyKYc-_9nb1zgWs4,10229
28
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/game-design/mechanics_design_patterns.md,sha256=sbBWhX8BQOIMyrYfdBjpjlhLeqE_vOuGQXXGFn-zY0U,4506
29
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/genre-conventions/children_and_ya_conventions.md,sha256=b5juJi2z3FMYKL5Tkw08E1jjtlvQdMy3sbDoU0PV88w,3680
30
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/genre-conventions/fantasy_conventions.md,sha256=AN-Mc9kkZKOE4qr8jwAyt6Yh5WlXqRFTPad0BS9joY0,13925
31
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/genre-conventions/historical_fiction.md,sha256=6mAgLSfAD2EV-UCE5WJM1Wk4ARsCuYofKR3Dn0Kcfhg,12016
32
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/genre-conventions/horror_conventions.md,sha256=449Ik17haBHnlIfGkh6FwDqoes8K-y7WKNimGxSq5yg,12883
33
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/genre-conventions/mystery_conventions.md,sha256=xZLCcO3MZJ4dghzoMbITZUc1A7xGpSL1B9LtR74Fhj4,12282
34
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/genre-conventions/sci_fi_conventions.md,sha256=dNkeIipLgtui2Xt6kPlEHT0HHNnCbPDFBQyH_5-1RfQ,5636
35
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/narrative-structure/branching_narrative_construction.md,sha256=Rv8t7zn4g3K6mF1NaHYXAX_vEAdUFcfa-aDA44bAOqs,22265
36
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/narrative-structure/branching_narrative_craft.md,sha256=I4APmDwCQ9dVF9blORxgF_YArfj9aSrTP8TpXJYI-jA,10906
37
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/narrative-structure/endings_patterns.md,sha256=RyxJfZuFyuyEKzmR32H9kBs4jUbeahwylNLkp2oiEjg,10581
38
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/narrative-structure/episodic_serialized_if.md,sha256=tEGRl-L3gRTXmbfoQZ-fCS2CR9xr-dHQgaQNcI4hHdA,9337
39
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/narrative-structure/nonlinear_structure.md,sha256=PfomsB5-l7DwGr1udbvgsTNdJaCdXgLhdYDvBUyKq2k,6287
40
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/narrative-structure/pacing_and_tension.md,sha256=0jlbJwzK2wNLxFQO4zHu6a53vM1Kwb6f5simamexKBU,9530
41
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/narrative-structure/romance_and_relationships.md,sha256=OW3nO9Qn_lCFWRGNyTKQMEOHnmuAA9rIo7wORaF_73U,4012
42
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/narrative-structure/scene_structure_and_beats.md,sha256=WL7buciBLTcl0vyTsLZcEgMI0U6ikA2t0EY9QkKpkJk,10094
43
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/narrative-structure/scene_transitions.md,sha256=Vu33QmpqWRnja4ITvcJepZ2f1NxK6fdwlroJUsczc1c,8500
44
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/prose-and-language/character_voice.md,sha256=gFQptHphCu9pZ2MzqaCVHvpSiHCefi4vBrwZtsfN0R8,11409
45
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/prose-and-language/dialogue_craft.md,sha256=4aQed24AQ7-VdYiaxjQ0JlK13qeNe3Gq1QgJiAqNEG4,11591
46
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/prose-and-language/exposition_techniques.md,sha256=T06IupDgh7MHQDkhHzo5U0ewDqGs5D60nGFn1V2NV-A,10023
47
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/prose-and-language/narrative_point_of_view.md,sha256=G_mZUPh4qxe3LdzO6hiFizJqbh4QKq6ukjcgTyeKPQ8,11020
48
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/prose-and-language/prose_patterns.md,sha256=UFEancpG4_TG3M7KnJGkZCvkafP6TxkhXEKEZgFPWug,10146
49
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/prose-and-language/subtext_and_implication.md,sha256=jKwBTZx5gVy84AG6x2hHmPwbFIiti419-DaDO4oXlH8,10726
50
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/prose-and-language/voice_register_consistency.md,sha256=JtY5bwIrrY1Cjy2ITGOGxCepDhoQnr7nzt2pqr2SKtI,9701
51
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/scope-and-planning/scope_and_length.md,sha256=fF6TDuLSJv5Uf7ov9_Eq0beh8OQF4RBEDmekjZbHkJQ,10315
52
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/world-and-setting/canon_management.md,sha256=ab1XjWXv3RzEWaChfUJOOSnRKjuQsUDaqYQ3T9bw9o0,10576
53
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/world-and-setting/setting_as_character.md,sha256=F0kM5EKlDldqPg2UyyfKx05fRyaWIoE-A-sIhl461Cw,9650
54
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/corpus/world-and-setting/worldbuilding_patterns.md,sha256=IpvZkT6sV3yC23RsICxpeMgb_FT_1mkv1z4NiHKNEIY,11905
55
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/subagents/README.md,sha256=FI9SqJfOg8hoO-3S_dpeIfepPRcd0fyquM7f5Y1J5eE,5817
56
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/subagents/if_genre_consultant.md,sha256=QshDQK4HkMNXYigU91r0CTosl5a-lKqvO9tQMFkbUFI,7244
57
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/subagents/if_platform_advisor.md,sha256=e_uV0vt5Nqah6bUNsiWVhmSuQeF0RIWAZOXJNygpeW8,8515
58
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/subagents/if_prose_writer.md,sha256=fjOazUCXvW62xrhZAsv7ynaDSpG_f1gGK2NJ0clJ1EQ,5927
59
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/subagents/if_quality_reviewer.md,sha256=PLPJtf-6t-jugN75k7EG7ln7S47TT0FcVjWVsRLGOz8,6992
60
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/subagents/if_story_architect.md,sha256=rF_U0Nd3tK0HzaLK6wGL36hRb0B6dfuc6lljAU9pmmo,4936
61
+ ifcraftcorpus-1.3.0.data/data/share/ifcraftcorpus/subagents/if_world_curator.md,sha256=xmbGF--5te8uxfimKFw45bFrhbdRM3LPaYBlhUd4swc,7376
62
+ ifcraftcorpus-1.3.0.dist-info/METADATA,sha256=-QqX06NPksR94gytqc7uS9wuR5OCTcYSNUkd2nfs5Sw,4989
63
+ ifcraftcorpus-1.3.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
64
+ ifcraftcorpus-1.3.0.dist-info/entry_points.txt,sha256=E8DYJ_qWOgPe758ULKth3gcYo-1XkNEvDomhFjJ-B-U,110
65
+ ifcraftcorpus-1.3.0.dist-info/licenses/LICENSE,sha256=7MoRwpgeEClx14esn2SJnOLz4jvxWP1uN_vjnC2XTHQ,1067
66
+ ifcraftcorpus-1.3.0.dist-info/licenses/LICENSE-CONTENT,sha256=jhGwmahhy9rUFJSSrLUrssnrfa-mXotvNEwq74i93x8,639
67
+ ifcraftcorpus-1.3.0.dist-info/RECORD,,