Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
2b0f694
feat(pov): Parzival 2.1 — shim architecture, dispatch skills, GC-19/G…
Mar 15, 2026
4d07c0b
docs(pov): update all Parzival docs for 2.1 + add 4 new skill guides
Mar 15, 2026
becfca3
fix(docs): adversarial review fixes + README Parzival section rewrite
Mar 15, 2026
cc78a6c
fix(docs): round 2 adversarial review — 8 fixes + restore teams_enabled
Mar 15, 2026
5568dbd
fix(docs): round 3 adversarial review — 5 fixes, convergence confirmed
Mar 16, 2026
afefd95
fix(docs): round 4 review — 4 remaining v1.x prompt-passing fixes
Mar 16, 2026
8960d8e
fix(installer): verify all system dependencies at install time
Mar 16, 2026
f62d498
fix: PLAN-018 Phase 1 — 6 bugs fixed, TD-296 thin shims, 15 review fi…
Mar 16, 2026
5bc06f7
fix: PLAN-018 Phase 2 — observability, config, security, 25 review fi…
Mar 16, 2026
922963d
fix(tests): resolve BUG-234 final caplog instance in test_classificat…
Mar 17, 2026
c114989
fix(lint): combine nested with statements in test_token_metrics (SIM117)
Mar 17, 2026
f9394ae
style: apply black 26.3.0 formatting to 8 PLAN-018 files
Mar 17, 2026
4488bb3
fix: PLAN-018 sprint fixes — BUG-219 source_type, M-12 gitignore, eva…
Mar 17, 2026
7d2eeb5
fix: single docker/.env source of truth — TD-308 .env architecture cl…
Mar 17, 2026
930c0ca
fix: isolate tests from real docker/.env + update docs for TD-308
Mar 17, 2026
87a1831
fix(lint): remove unused original_cwd variable in test_env_file_loading
Mar 17, 2026
4460932
style: apply black formatting to evaluator/provider.py
Mar 17, 2026
9c0eab7
fix: remove quotes from JIRA_PROJECTS comment that broke Docker Compo…
Mar 17, 2026
f82df0e
fix: remove inline comments from .env.example — Docker Compose and py…
Mar 17, 2026
91fbfbf
fix(docker): add tiktoken to github-sync requirements — BUG-236
Mar 17, 2026
3f0dce2
fix(config): uncomment and add missing compose-referenced vars in .en…
Mar 17, 2026
f5a2f65
docs: update CHANGELOG and TROUBLESHOOTING for BUG-236 and container …
Mar 18, 2026
d83de24
feat(pov): PLAN-019 Phases 1-5 + PLAN-020 sync — Parzival BMAD restru…
Mar 19, 2026
648b829
feat(pov): PLAN-019 Phase 6 — swap pov.restructured/ to pov/, fix all…
Mar 25, 2026
dd9ee50
fix(pov): optimize context loading + update docs for Phase 6
Mar 25, 2026
16691db
fix(installer): macOS/non-interactive pitfalls — BUG-238 through BUG-…
Mar 25, 2026
4a92ba5
fix(test): scope main() ordering test to actual function body
Mar 25, 2026
41496fd
fix(test): compare timed_operation against independent measurement
Mar 25, 2026
f240a9f
style: fix black formatting in test_logging.py
Mar 25, 2026
685b2de
fix(installer): extract sync_installed_files() to fix Option 1 missin…
Mar 26, 2026
8fb59f6
docs: update v2.3.0 upgrade instructions with tested container procedure
Mar 26, 2026
6748658
chore: version bump to v2.2.4 (was incorrectly set to v2.3.0)
Mar 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .claude/commands/pov/parzival-team.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: 'Design agent team structure for parallel work execution via Claude Code teams'
description: 'Design agent team structure for parallel work execution'
argument-hint: '<description of the work to parallelize>'
allowed-tools: Read, Grep, Glob, AskUserQuestion
---
Expand Down
12 changes: 12 additions & 0 deletions .claude/hooks/scripts/agent_response_store_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,18 @@ def store_agent_response(store_data: dict[str, Any]) -> bool:
"reason": "too_short_or_low_value",
},
)
try:
from memory.metrics_push import push_capture_metrics_async

push_capture_metrics_async(
hook_type="Stop",
status="quality_gate_skip",
project=detect_project(os.getcwd()) or "unknown",
collection="skipped",
count=1,
)
except ImportError:
pass
return True

# SPEC-021: Read trace_id from capture hook env propagation
Expand Down
2 changes: 1 addition & 1 deletion .claude/hooks/scripts/best_practices_retrieval.py
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ def main() -> int:
parent_span_id=None,
session_id=bp_session_id,
project_id=project_name,
tags=["search", "best_practices"],
tags=["retrieval", "best_practices"],
)
except Exception:
pass
Expand Down
3 changes: 2 additions & 1 deletion .claude/hooks/scripts/context_injection_tier2.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ def main() -> int:
budget=budget,
excluded_ids=state.injected_point_ids,
score_gap_threshold=config.injection_score_gap_threshold,
project_id=project_name,
)

# WP-2: Push freshness-blocked counter if any results were blocked this turn
Expand Down Expand Up @@ -437,7 +438,7 @@ def main() -> int:
return 0

# Format output
formatted = format_injection_output(selected, tier=2)
formatted = format_injection_output(selected, tier=2, project_id=project_name)

# Update session state
state.injected_point_ids.extend(str(r.get("id", "")) for r in selected)
Expand Down
2 changes: 1 addition & 1 deletion .claude/hooks/scripts/error_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ def main() -> int:
trace_id=uuid4().hex,
session_id=_err_session_id,
project_id=project_name,
tags=["injection", "error_detection"],
tags=["capture", "error_detection"],
)
except Exception:
logger.debug("trace_event_failed_error_fix_injection")
Expand Down
6 changes: 5 additions & 1 deletion .claude/hooks/scripts/langfuse_stop_hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,11 @@ def main():

# ── V3 SDK: Create root observation + child spans ──
# LANGFUSE-INTEGRATION-SPEC.md §7.1: Uses start_as_current_observation (V3)
from langfuse import get_client as _get_v3_client, propagate_attributes
try:
from langfuse import get_client as _get_v3_client, propagate_attributes
except ImportError:
logger.warning("langfuse_not_installed", extra={"message": "langfuse package not available, skipping trace emission"})
sys.exit(0)

langfuse_v3 = _get_v3_client()

Expand Down
15 changes: 14 additions & 1 deletion .claude/hooks/scripts/post_tool_capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -540,9 +540,22 @@ def main() -> int:
)

# Extract content based on tool type
# BUG-226: For Edit, read full file instead of just new_string
content = ""
if tool_name == "Edit":
content = tool_input.get("new_string", "")
# BUG-226: Read full file for richer context, fallback to new_string
_MAX_EDIT_READ = 200_000 # 200KB cap
if file_path:
try:
_fsize = Path(file_path).stat().st_size
if _fsize <= _MAX_EDIT_READ:
content = Path(file_path).read_text(encoding="utf-8", errors="replace")
else:
content = tool_input.get("new_string", "")
except OSError:
content = tool_input.get("new_string", "")
else:
content = tool_input.get("new_string", "")
elif tool_name == "Write":
content = tool_input.get("content", "")
elif tool_name == "NotebookEdit":
Expand Down
102 changes: 1 addition & 101 deletions .claude/hooks/scripts/session_start.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ def main():
parent_span_id=None,
session_id=session_id,
project_id=project_name,
tags=["injection", "resume"],
tags=["injection", "tier1", "bootstrap"],
)
except Exception:
pass
Expand Down Expand Up @@ -924,38 +924,6 @@ def main():
}
)

# TD-228: Per-search trace for session summaries (compact path)
if emit_trace_event:
try:
emit_trace_event(
event_type="memory_retrieval_sessions",
data={
"input": f"get_recent(discussions, type=session, agent_id={_compact_agent_id!r}, limit={_summary_limit}) for {project_name}",
"output": f"Retrieved {len(session_summaries)} session summaries",
"metadata": {
"trigger": trigger,
"collection": COLLECTION_DISCUSSIONS,
"query_type": "session",
"method": "get_recent",
"agent_id": _compact_agent_id,
"limit": _summary_limit,
"result_count": len(session_summaries),
"top_results": [
{
"type": s.get("type", "session"),
"content_preview": s.get("content", "")[:200],
}
for s in session_summaries[:5]
],
},
},
session_id=session_id,
project_id=project_name,
tags=["injection", "compact"],
)
except Exception:
pass

# Retrieve decisions (PLAN-015 §4.1 — non-Parzival gets max 3)
_decision_kwargs: dict = {
"collection": COLLECTION_DISCUSSIONS,
Expand Down Expand Up @@ -987,39 +955,6 @@ def main():
)
decisions = []

# TD-228: Per-search trace for decisions (compact path)
if emit_trace_event:
try:
emit_trace_event(
event_type="memory_retrieval_decisions",
data={
"input": f"get_recent(discussions, type=decision, agent_id={_compact_agent_id!r}, limit=3) for {project_name}",
"output": f"Retrieved {len(decisions)} decisions",
"metadata": {
"trigger": trigger,
"collection": COLLECTION_DISCUSSIONS,
"query_type": "decision",
"method": "get_recent",
"agent_id": _compact_agent_id,
"limit": 3,
"result_count": len(decisions),
"top_results": [
{
"type": d.get("type", "decision"),
"score": round(d.get("score", 0.0), 4),
"content_preview": d.get("content", "")[:200],
}
for d in decisions[:5]
],
},
},
session_id=session_id,
project_id=project_name,
tags=["injection", "compact"],
)
except Exception:
pass

_retrieval_ms = (time.perf_counter() - _retrieval_start) * 1000

# TD-228 compatible trace event
Expand Down Expand Up @@ -1114,41 +1049,6 @@ def main():
) + conversation_context.count("**Agent")
summary_count = conversation_context.count("**Summary")
total_count = message_count + summary_count

# TD-228: Greedy-fill trace event for compact injection
if emit_trace_event:
try:
_gf_input_count = len(session_summaries) + len(other_memories)
_gf_tokens_est = (len(conversation_context) + 2) // 3
_gf_dropped = max(0, _gf_input_count - total_count)
emit_trace_event(
event_type="greedy_fill",
data={
"input": f"inject_with_priority: {_gf_input_count} candidates, budget={config.token_budget} tokens",
"output": f"Selected {total_count} items ({summary_count} summaries, {message_count} messages), dropped {_gf_dropped}",
"metadata": {
"trigger": trigger,
"input_count": _gf_input_count,
"selected_count": total_count,
"dropped_count": _gf_dropped,
"summary_count": summary_count,
"message_count": message_count,
"tokens_used_est": _gf_tokens_est,
"budget": config.token_budget,
"budget_used_pct": (
round(_gf_tokens_est / config.token_budget * 100, 1)
if config.token_budget > 0
else 0
),
},
},
session_id=session_id,
project_id=project_name,
tags=["injection", "compact"],
)
except Exception:
pass

logger.info(
"conversation_context_injected",
extra={
Expand Down
24 changes: 12 additions & 12 deletions .claude/hooks/scripts/store_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ async def store_memory_async(hook_input: dict[str, Any]) -> None:
trace_id=trace_id,
session_id=session_id,
project_id=group_id,
tags=["capture", "store"],
tags=["capture", "trigger"],
)
except Exception:
pass
Expand Down Expand Up @@ -257,7 +257,7 @@ async def store_memory_async(hook_input: dict[str, Any]) -> None:
trace_id=trace_id,
session_id=session_id,
project_id=group_id,
tags=["capture", "store"],
tags=["capture", "trigger"],
)
except Exception:
pass
Expand Down Expand Up @@ -321,7 +321,7 @@ async def store_memory_async(hook_input: dict[str, Any]) -> None:
trace_id=trace_id,
session_id=session_id,
project_id=group_id,
tags=["capture", "store"],
tags=["capture", "trigger"],
)
except Exception:
pass
Expand Down Expand Up @@ -356,7 +356,7 @@ async def store_memory_async(hook_input: dict[str, Any]) -> None:
trace_id=trace_id,
session_id=session_id,
project_id=group_id,
tags=["capture", "store"],
tags=["capture", "trigger"],
)
except Exception:
pass
Expand All @@ -378,7 +378,7 @@ async def store_memory_async(hook_input: dict[str, Any]) -> None:
from memory.security_scanner import ScanAction, SecurityScanner

scanner = SecurityScanner(enable_ner=False)
scan_result = scanner.scan(patterns["content"])
scan_result = scanner.scan(patterns["content"], source_type="user_session")
scan_actually_ran = True
# SPEC-021: Capture scan outcome for 4_scan span
scan_action = (
Expand Down Expand Up @@ -422,7 +422,7 @@ async def store_memory_async(hook_input: dict[str, Any]) -> None:
trace_id=trace_id,
session_id=session_id,
project_id=group_id,
tags=["capture", "store"],
tags=["capture", "trigger"],
)
except Exception:
pass
Expand All @@ -446,7 +446,7 @@ async def store_memory_async(hook_input: dict[str, Any]) -> None:
trace_id=trace_id,
session_id=session_id,
project_id=group_id,
tags=["capture", "store"],
tags=["capture", "trigger"],
)
except Exception:
pass
Expand Down Expand Up @@ -494,7 +494,7 @@ async def store_memory_async(hook_input: dict[str, Any]) -> None:
trace_id=trace_id,
session_id=session_id,
project_id=group_id,
tags=["capture", "store"],
tags=["capture", "trigger"],
)
except Exception:
pass
Expand Down Expand Up @@ -544,7 +544,7 @@ async def store_memory_async(hook_input: dict[str, Any]) -> None:
trace_id=trace_id,
session_id=session_id,
project_id=group_id,
tags=["capture", "store"],
tags=["capture", "trigger"],
)
except Exception:
pass
Expand Down Expand Up @@ -676,7 +676,7 @@ def _generate_embedding(content):
trace_id=trace_id,
session_id=session_id,
project_id=group_id,
tags=["capture", "store"],
tags=["capture", "trigger"],
)
except Exception:
pass
Expand Down Expand Up @@ -706,7 +706,7 @@ def _generate_embedding(content):
trace_id=trace_id,
session_id=session_id,
project_id=group_id,
tags=["capture", "store"],
tags=["capture", "trigger"],
)
except Exception:
pass
Expand Down Expand Up @@ -776,7 +776,7 @@ def _generate_embedding(content):
trace_id=trace_id,
session_id=session_id,
project_id=group_id,
tags=["capture", "store"],
tags=["capture", "trigger"],
)
except Exception:
pass
Expand Down
12 changes: 12 additions & 0 deletions .claude/hooks/scripts/user_prompt_store_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,18 @@ def store_user_message(hook_input: dict[str, Any]) -> bool:
"reason": "too_short_or_low_value",
},
)
try:
from memory.metrics_push import push_capture_metrics_async

push_capture_metrics_async(
hook_type="UserPromptSubmit",
status="quality_gate_skip",
project=detect_project(os.getcwd()) or "unknown",
collection="skipped",
count=1,
)
except ImportError:
pass
return True

# Detect project name
Expand Down
Loading
Loading