buildlog 0.6.1__py3-none-any.whl → 0.8.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 (40) hide show
  1. buildlog/__init__.py +1 -1
  2. buildlog/cli.py +589 -44
  3. buildlog/confidence.py +27 -0
  4. buildlog/core/__init__.py +12 -0
  5. buildlog/core/bandit.py +699 -0
  6. buildlog/core/operations.py +499 -11
  7. buildlog/distill.py +80 -1
  8. buildlog/engine/__init__.py +61 -0
  9. buildlog/engine/bandit.py +23 -0
  10. buildlog/engine/confidence.py +28 -0
  11. buildlog/engine/embeddings.py +28 -0
  12. buildlog/engine/experiments.py +619 -0
  13. buildlog/engine/types.py +31 -0
  14. buildlog/llm.py +461 -0
  15. buildlog/mcp/server.py +12 -6
  16. buildlog/mcp/tools.py +166 -13
  17. buildlog/render/__init__.py +19 -2
  18. buildlog/render/claude_md.py +74 -26
  19. buildlog/render/continue_dev.py +102 -0
  20. buildlog/render/copilot.py +100 -0
  21. buildlog/render/cursor.py +105 -0
  22. buildlog/render/tracking.py +20 -1
  23. buildlog/render/windsurf.py +95 -0
  24. buildlog/seeds.py +41 -0
  25. buildlog/skills.py +69 -6
  26. {buildlog-0.6.1.data → buildlog-0.8.0.data}/data/share/buildlog/copier.yml +0 -4
  27. buildlog-0.8.0.data/data/share/buildlog/template/buildlog/_TEMPLATE_QUICK.md +21 -0
  28. buildlog-0.8.0.dist-info/METADATA +151 -0
  29. buildlog-0.8.0.dist-info/RECORD +54 -0
  30. buildlog-0.6.1.dist-info/METADATA +0 -490
  31. buildlog-0.6.1.dist-info/RECORD +0 -41
  32. {buildlog-0.6.1.data → buildlog-0.8.0.data}/data/share/buildlog/post_gen.py +0 -0
  33. {buildlog-0.6.1.data → buildlog-0.8.0.data}/data/share/buildlog/template/buildlog/.gitkeep +0 -0
  34. {buildlog-0.6.1.data → buildlog-0.8.0.data}/data/share/buildlog/template/buildlog/2026-01-01-example.md +0 -0
  35. {buildlog-0.6.1.data → buildlog-0.8.0.data}/data/share/buildlog/template/buildlog/BUILDLOG_SYSTEM.md +0 -0
  36. {buildlog-0.6.1.data → buildlog-0.8.0.data}/data/share/buildlog/template/buildlog/_TEMPLATE.md +0 -0
  37. {buildlog-0.6.1.data → buildlog-0.8.0.data}/data/share/buildlog/template/buildlog/assets/.gitkeep +0 -0
  38. {buildlog-0.6.1.dist-info → buildlog-0.8.0.dist-info}/WHEEL +0 -0
  39. {buildlog-0.6.1.dist-info → buildlog-0.8.0.dist-info}/entry_points.txt +0 -0
  40. {buildlog-0.6.1.dist-info → buildlog-0.8.0.dist-info}/licenses/LICENSE +0 -0
buildlog/distill.py CHANGED
@@ -8,6 +8,7 @@ __all__ = [
8
8
  "distill_all",
9
9
  "format_output",
10
10
  "parse_improvements",
11
+ "parse_improvements_llm",
11
12
  "parse_date_from_filename",
12
13
  "iter_buildlog_entries",
13
14
  ]
@@ -19,7 +20,10 @@ from collections.abc import Iterator
19
20
  from dataclasses import dataclass, field
20
21
  from datetime import date, datetime, timezone
21
22
  from pathlib import Path
22
- from typing import Final, Literal, TypedDict
23
+ from typing import TYPE_CHECKING, Final, Literal, TypedDict
24
+
25
+ if TYPE_CHECKING:
26
+ from buildlog.llm import ExtractedRule, LLMBackend
23
27
 
24
28
  logger = logging.getLogger(__name__)
25
29
 
@@ -191,6 +195,36 @@ def parse_improvements(content: str) -> dict[str, list[str]]:
191
195
  return result
192
196
 
193
197
 
198
+ def parse_improvements_llm(content: str, backend: LLMBackend) -> list[ExtractedRule]:
199
+ """Extract improvements using an LLM backend for richer extraction.
200
+
201
+ Sends the Improvements section to the LLM for structured extraction
202
+ of rules with severity, scope, applicability, and defensibility fields.
203
+
204
+ Args:
205
+ content: The full markdown content of a buildlog entry.
206
+ backend: An LLM backend implementing the LLMBackend protocol.
207
+
208
+ Returns:
209
+ List of ExtractedRule objects with rich metadata.
210
+ """
211
+ # Extract the Improvements section
212
+ improvements_match = re.search(
213
+ r"^##\s+Improvements\s*\n(.*?)(?=^#{1,2}\s|\Z)",
214
+ content,
215
+ re.MULTILINE | re.DOTALL,
216
+ )
217
+
218
+ if not improvements_match:
219
+ return []
220
+
221
+ improvements_text = improvements_match.group(1).strip()
222
+ if not improvements_text:
223
+ return []
224
+
225
+ return backend.extract_rules(improvements_text)
226
+
227
+
194
228
  def parse_date_from_filename(filename: str) -> str | None:
195
229
  """Extract date from buildlog filename (YYYY-MM-DD-slug.md format)."""
196
230
  match = re.match(r"^(\d{4}-\d{2}-\d{2})-", filename)
@@ -290,6 +324,7 @@ def distill_all(
290
324
  buildlog_dir: Path,
291
325
  since: date | None = None,
292
326
  category_filter: str | None = None,
327
+ llm: bool = False,
293
328
  ) -> DistillResult:
294
329
  """Parse all buildlog entries and aggregate patterns.
295
330
 
@@ -297,10 +332,23 @@ def distill_all(
297
332
  buildlog_dir: Path to the buildlog directory.
298
333
  since: If provided, only include entries from this date onward.
299
334
  category_filter: If provided, only include patterns from this category.
335
+ llm: If True and an LLM backend is available, use LLM extraction.
336
+ Falls back to regex on failure or if no backend is available.
300
337
 
301
338
  Returns:
302
339
  DistillResult with aggregated patterns and statistics.
303
340
  """
341
+ # Resolve LLM backend if requested
342
+ llm_backend: LLMBackend | None = None
343
+ if llm:
344
+ from buildlog.llm import get_llm_backend
345
+
346
+ llm_backend = get_llm_backend(buildlog_dir=buildlog_dir)
347
+ if llm_backend is None:
348
+ logger.warning(
349
+ "--llm requested but no LLM provider available, using regex fallback"
350
+ )
351
+
304
352
  patterns: dict[str, list[PatternDict]] = {cat: [] for cat in CATEGORIES}
305
353
  by_month: dict[str, int] = {}
306
354
  entry_count = 0
@@ -318,6 +366,37 @@ def distill_all(
318
366
  month_key = _extract_month_key(date_str)
319
367
  by_month[month_key] = by_month.get(month_key, 0) + 1
320
368
 
369
+ # Try LLM extraction first, fall back to regex
370
+ if llm_backend is not None:
371
+ try:
372
+ extracted = parse_improvements_llm(content, llm_backend)
373
+ if extracted:
374
+ # Convert ExtractedRule objects to standard PatternDict format
375
+ for rule in extracted:
376
+ cat = (
377
+ rule.category
378
+ if rule.category in CATEGORIES
379
+ else "architectural"
380
+ )
381
+ if cat not in patterns:
382
+ patterns[cat] = []
383
+ patterns[cat].append(
384
+ PatternDict(
385
+ insight=rule.rule,
386
+ source=str(entry_path),
387
+ date=date_str,
388
+ context=context,
389
+ )
390
+ )
391
+ continue # Skip regex if LLM succeeded
392
+ except Exception as e:
393
+ logger.warning(
394
+ "LLM extraction failed for %s, falling back to regex: %s",
395
+ entry_path,
396
+ e,
397
+ )
398
+
399
+ # Regex fallback (default behavior)
321
400
  try:
322
401
  improvements = parse_improvements(content)
323
402
  except re.error as e:
@@ -0,0 +1,61 @@
1
+ """Buildlog Engine — agent-agnostic core for rule learning and experiment tracking.
2
+
3
+ This package provides the pure algorithmic core of buildlog without any
4
+ CLI, copier, or agent-specific rendering dependencies. Use it when you
5
+ want Thompson Sampling bandits, confidence scoring, embedding similarity,
6
+ or experiment tracking in your own tools.
7
+
8
+ Usage:
9
+ from buildlog.engine import ThompsonSamplingBandit, BetaParams
10
+ from buildlog.engine import calculate_confidence, ConfidenceMetrics
11
+ from buildlog.engine import start_session, end_session, log_mistake
12
+ from buildlog.engine.types import Skill, Session, Mistake, RewardEvent
13
+
14
+ Install:
15
+ pip install buildlog # engine is part of the base package
16
+ pip install buildlog[engine] # same thing — documents the namespace
17
+ """
18
+
19
+ from buildlog.engine.bandit import BetaParams, ThompsonSamplingBandit
20
+ from buildlog.engine.confidence import (
21
+ ConfidenceConfig,
22
+ ConfidenceMetrics,
23
+ calculate_confidence,
24
+ get_confidence_tier,
25
+ merge_confidence_metrics,
26
+ )
27
+ from buildlog.engine.experiments import (
28
+ end_session,
29
+ experiment_report,
30
+ get_rewards,
31
+ log_mistake,
32
+ log_reward,
33
+ session_metrics,
34
+ start_session,
35
+ )
36
+ from buildlog.engine.types import Mistake, RewardEvent, Session, Skill
37
+
38
+ __all__ = [
39
+ # Bandit
40
+ "ThompsonSamplingBandit",
41
+ "BetaParams",
42
+ # Confidence
43
+ "calculate_confidence",
44
+ "get_confidence_tier",
45
+ "merge_confidence_metrics",
46
+ "ConfidenceMetrics",
47
+ "ConfidenceConfig",
48
+ # Experiments
49
+ "start_session",
50
+ "end_session",
51
+ "log_mistake",
52
+ "log_reward",
53
+ "get_rewards",
54
+ "session_metrics",
55
+ "experiment_report",
56
+ # Types
57
+ "Skill",
58
+ "Session",
59
+ "Mistake",
60
+ "RewardEvent",
61
+ ]
@@ -0,0 +1,23 @@
1
+ """Re-export Thompson Sampling bandit from core.
2
+
3
+ Provides clean access to the bandit without reaching into core internals.
4
+
5
+ Usage:
6
+ from buildlog.engine.bandit import ThompsonSamplingBandit, BetaParams
7
+ """
8
+
9
+ from buildlog.core.bandit import (
10
+ DEFAULT_CONTEXT,
11
+ DEFAULT_SEED_BOOST,
12
+ BanditState,
13
+ BetaParams,
14
+ ThompsonSamplingBandit,
15
+ )
16
+
17
+ __all__ = [
18
+ "ThompsonSamplingBandit",
19
+ "BetaParams",
20
+ "BanditState",
21
+ "DEFAULT_SEED_BOOST",
22
+ "DEFAULT_CONTEXT",
23
+ ]
@@ -0,0 +1,28 @@
1
+ """Re-export confidence scoring from buildlog.confidence.
2
+
3
+ Provides clean access to confidence calculation without reaching into
4
+ top-level module internals.
5
+
6
+ Usage:
7
+ from buildlog.engine.confidence import calculate_confidence, ConfidenceMetrics
8
+ """
9
+
10
+ from buildlog.confidence import (
11
+ ConfidenceConfig,
12
+ ConfidenceMetrics,
13
+ ConfidenceTier,
14
+ add_contradiction,
15
+ calculate_confidence,
16
+ get_confidence_tier,
17
+ merge_confidence_metrics,
18
+ )
19
+
20
+ __all__ = [
21
+ "calculate_confidence",
22
+ "get_confidence_tier",
23
+ "merge_confidence_metrics",
24
+ "add_contradiction",
25
+ "ConfidenceMetrics",
26
+ "ConfidenceConfig",
27
+ "ConfidenceTier",
28
+ ]
@@ -0,0 +1,28 @@
1
+ """Re-export embedding backends from buildlog.embeddings.
2
+
3
+ Provides clean access to embedding similarity without reaching into
4
+ top-level module internals.
5
+
6
+ Usage:
7
+ from buildlog.engine.embeddings import similarity, TokenBackend
8
+ """
9
+
10
+ from buildlog.embeddings import (
11
+ EmbeddingBackend,
12
+ OpenAIBackend,
13
+ SentenceTransformerBackend,
14
+ TokenBackend,
15
+ compute_embeddings,
16
+ get_backend,
17
+ similarity,
18
+ )
19
+
20
+ __all__ = [
21
+ "EmbeddingBackend",
22
+ "TokenBackend",
23
+ "SentenceTransformerBackend",
24
+ "OpenAIBackend",
25
+ "get_backend",
26
+ "similarity",
27
+ "compute_embeddings",
28
+ ]