threadkeeper 0.19.0__tar.gz → 0.19.1__tar.gz
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.
- {threadkeeper-0.19.0/threadkeeper.egg-info → threadkeeper-0.19.1}/PKG-INFO +173 -51
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/README.md +172 -50
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/pyproject.toml +1 -1
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_agent_status.py +36 -17
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_config_settings.py +3 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_curator.py +187 -5
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_evolve_applier.py +388 -8
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_evolve_daemon.py +163 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_identity.py +2 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_ingest_denylist.py +1 -1
- threadkeeper-0.19.1/tests/test_mcp_protocol_conformance.py +235 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_mcp_resources_prompts.py +160 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_memory_eval.py +84 -4
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_nudges.py +4 -7
- threadkeeper-0.19.1/tests/test_project_scope.py +113 -0
- threadkeeper-0.19.1/tests/test_session_read_purity.py +104 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_shadow_review.py +6 -1
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_skill_hint.py +4 -5
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_hint.py +9 -16
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_tool_annotations.py +53 -1
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_tools_smoke.py +1 -0
- threadkeeper-0.19.1/tests/test_tracing.py +237 -0
- threadkeeper-0.19.1/tests/test_workflow_retention.py +255 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/_mcp.py +84 -3
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/_spawn_wrap.py +9 -3
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/base.py +1 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/agent_status.py +37 -20
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/brief.py +50 -41
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/candidate_reviewer.py +9 -6
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/config.py +29 -6
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/curator.py +214 -76
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/curator_snapshots.py +44 -3
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/db.py +246 -16
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/dialectic_miner.py +10 -5
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/dialectic_validator.py +4 -2
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/elicitation.py +3 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/embeddings.py +12 -4
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/evolve_applier.py +426 -53
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/evolve_daemon.py +60 -27
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/forget.py +13 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/identity.py +13 -3
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/ingest.py +20 -4
- threadkeeper-0.19.1/threadkeeper/project_scope.py +204 -0
- threadkeeper-0.19.1/threadkeeper/protocol.py +186 -0
- threadkeeper-0.19.1/threadkeeper/read_context.py +24 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/retention.py +5 -1
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/retrieval.py +34 -8
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/server.py +1 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/shadow_review.py +4 -1
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/spawn_budget.py +1 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/sync/identity.py +6 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tool_schemas.py +1 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/agent_status.py +15 -2
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/concepts.py +25 -10
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/core_memory.py +43 -16
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/curator.py +7 -4
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/dashboard.py +6 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/db_maintenance.py +19 -1
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/dialectic.py +39 -13
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/dialog.py +24 -7
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/distill.py +26 -10
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/evolve_applier.py +33 -20
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/extract.py +44 -25
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/pickup.py +4 -3
- threadkeeper-0.19.1/threadkeeper/tools/project_scope.py +33 -0
- threadkeeper-0.19.1/threadkeeper/tools/resources.py +460 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/session.py +8 -3
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/shadow_review.py +28 -11
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/spawn.py +64 -9
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/style.py +14 -2
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/sync.py +2 -2
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/threads.py +60 -22
- threadkeeper-0.19.1/threadkeeper/tracing.py +572 -0
- threadkeeper-0.19.1/threadkeeper/workflow_artifacts.py +568 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1/threadkeeper.egg-info}/PKG-INFO +173 -51
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper.egg-info/SOURCES.txt +10 -0
- threadkeeper-0.19.0/tests/test_session_read_purity.py +0 -51
- threadkeeper-0.19.0/threadkeeper/tools/resources.py +0 -100
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/LICENSE +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/setup.cfg +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_adapters.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_antigravity_ingest.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_auto_update.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_backup.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_brief_footprint.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_brief_sections.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_candidate_reviewer.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_ci_parallel.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_concepts.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_config_watcher.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_core_memory.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_daemon_host_config.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_daemon_host_integration.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_daemon_liveness.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_daemon_state.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dashboard.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_db_compact.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_db_contention.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_db_leak_guard.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_db_migration_fts.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_db_runtime.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_db_schema.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_delegated_search.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dialectic.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dialectic_feed_tools.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dialectic_miner.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dialectic_observation_resolve.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dialectic_recompute.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dialectic_tier.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dialectic_validator.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dialog_fts_external.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_documentation_inventory.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_egress_policy.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_embed_routing.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_embedding_generation.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_embedding_model_revision.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_embedding_storage_dedup.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_error_paths.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_eval_harness.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_evolve_apply_2.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_evolve_apply_3.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_evolve_apply_43.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_evolve_apply_45.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_extract_daemon.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_extract_dedup.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_forget.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_github_budget.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_github_safety.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_helpers.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_hook_child_guard.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_host_embed.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_host_env.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_host_main.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_host_wedged.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_hybrid_retrieval.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_i18n_multilang.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_ingest_cursor.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_ingest_secret_redaction.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_ingest_status.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_ingest_transactions.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_lesson_violations.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_lessons.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_mcp_sdk_compat.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_mcp_skills_extension.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_memory_authority_lifecycle.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_memory_compatibility.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_memory_guard.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_memory_guard_host.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_menubar_app.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_missed_spawns.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_model_catalog.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_notify_daemon.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_onnx_embeddings.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_panel.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_permissions.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_pickup.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_probe_daemon.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_process_health.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_release_workflows.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_retention.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_review_prompts.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_search_fts_punctuation.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_setup.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_single_flight_prompt_prefixes.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_skill_passive_tier.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_skill_tier.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_skill_updater.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_skill_use_parser.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_skill_watcher.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_skills.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_background_cwd.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_budget.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_child_env.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_codex_stdin.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_config.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_permission_gate.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_reap.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_result.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_slim.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_watchdog.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_worktree_isolation.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_wrap.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_sync_capture.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_sync_identity.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_sync_migrate.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_sync_protocol.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_sync_reset_node.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_sync_transport.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_task_retention.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_task_spool.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_thin_session.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_thread_janitor.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_threads.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_validate_threads.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_vec_search.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_verify_ingest.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/__init__.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/_setup.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/__init__.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/_hook_helpers.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/antigravity.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/claude_code.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/claude_desktop.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/codex.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/copilot.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/vscode.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/agent_metadata.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/assets/macos-agent-status/Info.plist +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/assets/macos-agent-status/README.md +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/assets/macos-agent-status/ThreadKeeperAgentStatus.swift +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/assets/macos-agent-status/build.sh +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/assets/macos-agent-status/install.sh +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/authority.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/auto_update.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/backup.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/config_io.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/config_watcher.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/daemon_liveness.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/daemon_state.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/daemon_supervisor.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/egress.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/eval/__init__.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/eval/__main__.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/eval/harness.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/extract_daemon.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/github_budget.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/github_safety.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/harvest.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/helpers.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/host.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/host_embed.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/i18n.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/lesson_violations.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/lessons.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/link_health.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/mcp_skills.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/memory_compat.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/memory_guard.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/menubar_app.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/migrate_embeddings.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/model_catalog.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/notify.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/nudges.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/permissions.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/probe_daemon.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/process_health.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/review_prompts.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/search_proxy.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/skill_audit.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/skill_updater.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/skill_watcher.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/spawn_config.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/spawn_result.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/sync/__init__.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/sync/capture.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/sync/daemon.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/sync/migrate.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/sync/protocol.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/sync/reset_node.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/sync/server.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/task_spool.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/thread_janitor.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/__init__.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/authority.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/candidate_reviewer.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/config_watch.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/consolidate.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/correlation.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/dialectic_feed.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/evolve_research.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/forget.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/graph.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/invariants.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/lessons.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/memory_guard.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/missed_spawns.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/panel.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/peers.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/probes.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/process_health.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/prompts.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/skills.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/validate.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/trash.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/verify_ingest.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/wikilinks.py +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper.egg-info/dependency_links.txt +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper.egg-info/entry_points.txt +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper.egg-info/requires.txt +0 -0
- {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: threadkeeper
|
|
3
|
-
Version: 0.19.
|
|
3
|
+
Version: 0.19.1
|
|
4
4
|
Summary: Multi-agent shared brain across Claude Code/Desktop, Codex, Antigravity CLI, Copilot, and VS Code. Cross-session memory, self-improving skill loops, inter-agent signaling — one local MCP server.
|
|
5
5
|
Author: thread-keeper contributors
|
|
6
6
|
License: MIT
|
|
@@ -232,7 +232,7 @@ read/act split, plus MCP elicitation for host-native confirmations:
|
|
|
232
232
|
| Primitive | Control | What thread-keeper exposes | When to use |
|
|
233
233
|
|---|---|---|---|
|
|
234
234
|
| **Tools** | model-controlled (may act) | the full surface — `brief`, `note`, `spawn`, `search`, `curator_review`, `wikilink_health`, … | the agent decides to call them |
|
|
235
|
-
| **Resources** | application-controlled, read-only | `memory://brief`, `memory://context`, `memory://dashboard`, `memory://agent-status` | the **host** attaches/pulls them automatically |
|
|
235
|
+
| **Resources** | application-controlled, read-only | `memory://brief`, `memory://context`, `memory://dashboard`, `memory://agent-status` | the **host** attaches/pulls them automatically; capable hosts may subscribe |
|
|
236
236
|
| **Prompts** | user-controlled templates | `review_recent_threads`, `run_library_curation`, `audit_threadkeeper` | the user runs them (Claude Code: `/mcp__thread-keeper__<name>`) |
|
|
237
237
|
|
|
238
238
|
**Resources** back the genuinely read-only memory views with the same render
|
|
@@ -322,6 +322,28 @@ override wins over `.env`):
|
|
|
322
322
|
THREADKEEPER_MEMORY_EGRESS=same-vendor
|
|
323
323
|
```
|
|
324
324
|
|
|
325
|
+
### Project memory boundaries
|
|
326
|
+
|
|
327
|
+
Memory is also isolated by repository. thread-keeper derives a path-free
|
|
328
|
+
`prj_…` namespace from the repository remote (or, when no remote exists, its
|
|
329
|
+
Git history), so ordinary moves and Git worktrees retain one identity without
|
|
330
|
+
storing a local path. New project memory is scoped to that namespace; portable
|
|
331
|
+
memory must be explicitly written as `global` or `shared`.
|
|
332
|
+
|
|
333
|
+
`brief()`, `search()`, `dialog_search()`, resources, and learning-loop inputs
|
|
334
|
+
read the current project plus explicit global/shared rows. Set
|
|
335
|
+
`cross_project=True` on `search` or `dialog_search` only for deliberate
|
|
336
|
+
cross-project recall. Those results show `scope=`/`project=` provenance and
|
|
337
|
+
write a `cross_project_recall` audit event. The `memory_scope_status()` tool
|
|
338
|
+
shows the current namespace and the migration accounting.
|
|
339
|
+
|
|
340
|
+
Existing databases are migrated conservatively: rows without reliable
|
|
341
|
+
repository provenance are marked `unresolved`, excluded from automatic recall,
|
|
342
|
+
and listed in the migration report until an operator classifies them. This
|
|
343
|
+
boundary controls *which local memory is recalled*; it is separate from
|
|
344
|
+
`THREADKEEPER_MEMORY_EGRESS`, which controls whether personal memory may be
|
|
345
|
+
sent to another model provider.
|
|
346
|
+
|
|
325
347
|
---
|
|
326
348
|
|
|
327
349
|
## Core systems
|
|
@@ -764,15 +786,20 @@ for semantic review. System and installed-plugin sources are resolved from
|
|
|
764
786
|
their read-only caches rather than misreported as missing mirrors; telemetry
|
|
765
787
|
rows with no real `SKILL.md` remain explicit orphans. The same inventory also
|
|
766
788
|
flags a dense lesson subtopic when at least
|
|
767
|
-
`THREADKEEPER_CURATOR_PROMOTION_MIN_LESSONS` lessons (default 3) share
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
789
|
+
`THREADKEEPER_CURATOR_PROMOTION_MIN_LESSONS` lessons (default 3) share two
|
|
790
|
+
concrete title terms and a non-generic body mechanism. Generic joins and
|
|
791
|
+
domain-wide/high-document-frequency title words cannot form a candidate. The
|
|
792
|
+
inventory and `curator_review_status()` report emitted/rejected counts and
|
|
793
|
+
rejection reasons, so the rule can be tuned from production data. A
|
|
794
|
+
non-protected candidate must become one validated, checklist-style canonical
|
|
795
|
+
skill before its source lessons are retired; protected clusters are left for
|
|
796
|
+
human review. The evaluator reads every complete skill and relevant support
|
|
797
|
+
file, but has no web tools. External research is off by default. With explicit
|
|
798
|
+
`THREADKEEPER_CURATOR_WEB_RESEARCH=1`, a separate Claude-only researcher gets
|
|
799
|
+
only fixed public compatibility queries, `WebSearch`, `WebFetch`, and one
|
|
800
|
+
parent-authorized handoff writer; it cannot read local memory or the
|
|
801
|
+
repository. The evaluator receives that handoff as fenced, untrusted data and
|
|
802
|
+
writes numbered per-skill verdicts to
|
|
776
803
|
`~/.threadkeeper/curator/REPORT-<isodate>.md` for a one-batch pass or
|
|
777
804
|
`REPORT-<isodate>-batch-NNN-of-MMM.md` for a multi-batch pass: KEEP / REPAIR /
|
|
778
805
|
UPDATE / MERGE / SPLIT / DEPRECATE / DELETE / CROSS_LINK / HUMAN_REVIEW.
|
|
@@ -874,7 +901,11 @@ a recoverable snapshot under
|
|
|
874
901
|
`~/.threadkeeper/curator/snapshots/<pass-id>/`). The snapshot contains
|
|
875
902
|
`lessons.md`, copied in-scope skill dirs, a `manifest.json`, and per-action
|
|
876
903
|
tombstones for curator prunes/deletes. Retention is bounded by
|
|
877
|
-
`THREADKEEPER_CURATOR_SNAPSHOT_RETENTION` (default 10
|
|
904
|
+
`THREADKEEPER_CURATOR_SNAPSHOT_RETENTION` (default 10) for legacy/direct
|
|
905
|
+
snapshots. Daemon-owned snapshots instead follow the coordinated workflow
|
|
906
|
+
retention policy, so their pass, report, manifest, and recovery archive cannot
|
|
907
|
+
age out on different schedules; active work and an endorsed report that has not
|
|
908
|
+
been applied always keep recovery material.
|
|
878
909
|
Use `curator_restore(pass_id, lesson_slug="...")` or
|
|
879
910
|
`curator_restore(pass_id, skill_name="...")` to restore an item from a snapshot.
|
|
880
911
|
As a prevention layer before recovery is needed, a destructive Curator pass
|
|
@@ -1011,15 +1042,27 @@ with that name instead of minting overlapping roadmap PRs.
|
|
|
1011
1042
|
|
|
1012
1043
|
The Evolve applier is the downstream implementer. `evolve_apply_roadmap_issue()`
|
|
1013
1044
|
picks one open GitHub issue at a time (`roadmap` label first, then FIFO), but
|
|
1014
|
-
the automatic pass first
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1045
|
+
the automatic pass first sweeps the open PRs authored by the account
|
|
1046
|
+
thread-keeper's `gh` acts as — yours: applier, reviewer, and hand-made PRs
|
|
1047
|
+
alike. A PR from any other account (a collaborator, a bot, a fork) is never
|
|
1048
|
+
updated, repaired, or merged. If the PR sweep itself cannot read GitHub state
|
|
1049
|
+
or the `gh` account, the pass fails closed instead of taking fresh work blind.
|
|
1050
|
+
The sweep squash-merges the oldest non-draft PR GitHub reports `CLEAN` (up to
|
|
1051
|
+
date, required checks green) through the protected merge API, pinned to the
|
|
1052
|
+
head SHA it saw green, and then asks GitHub to update the oldest `BEHIND` one —
|
|
1053
|
+
the "Update branch" button — so CI reruns against the new base. Open
|
|
1054
|
+
work in progress as a draft: drafts are never merged. Strict branch
|
|
1055
|
+
protection lets only one PR merge per base commit, so PRs land one at a time,
|
|
1056
|
+
oldest first. Between full passes the daemon repeats only this cheap landing
|
|
1057
|
+
sweep every 15 minutes, so a green PR lands minutes after its checks finish;
|
|
1058
|
+
it skips while any reviewer/applier git writer runs. A conflicted applier PR
|
|
1059
|
+
(`roadmap/…` or `evolve/…` head branch in this repository) is repaired before
|
|
1060
|
+
any new issue/report/evolve work is started: the conflict-repair child checks
|
|
1061
|
+
out the existing PR branch, merges the current base branch, resolves
|
|
1062
|
+
conflicts, runs the full suite, and pushes back to the same branch, then
|
|
1063
|
+
stops; the landing sweep merges it once it is green. A hand-made PR with
|
|
1064
|
+
conflicts, and red or otherwise blocked PRs, wait for a human. Set
|
|
1065
|
+
`THREADKEEPER_EVOLVE_AUTOLAND=0` to leave every merge to a human.
|
|
1023
1066
|
The roadmap issue child skips issues carrying denylisted human-gate labels,
|
|
1024
1067
|
skips issues with an active Evolve claim comment, posts its own claim comment
|
|
1025
1068
|
before spawning, and advances to the next issue when an issue-local dispatch
|
|
@@ -1054,9 +1097,13 @@ task’s tree. This prevents unrelated unfinished tests from blocking every PR
|
|
|
1054
1097
|
repair. Ignored files (including `.venv`) and explicit operator checkouts stay
|
|
1055
1098
|
in place; live writers prevent recovery, and backup failures block dispatch.
|
|
1056
1099
|
Each managed-checkout child fetches the
|
|
1057
|
-
configured branch
|
|
1058
|
-
|
|
1059
|
-
|
|
1100
|
+
configured branch, prepares or resumes its deterministic local/remote feature
|
|
1101
|
+
branch from the freshly fetched `origin/<THREADKEEPER_EVOLVE_REPO_BRANCH>` tip,
|
|
1102
|
+
rebases onto it, and re-syncs the managed venv to that branch's declared
|
|
1103
|
+
dependencies. `THREADKEEPER_EVOLVE_REPO_COMMIT` bounds only what the parent
|
|
1104
|
+
provisions and parks the checkout at; it is never a branch base, because a base
|
|
1105
|
+
that never moves cut every applier PR from one stale commit and each PR was
|
|
1106
|
+
born conflicted with `main`. Retries
|
|
1060
1107
|
therefore validate prior branch work instead of discovering a branch-name
|
|
1061
1108
|
collision after changing the base checkout. A shared git-writer running-task
|
|
1062
1109
|
check prevents the privileged reviewer audit and code/PR applier from
|
|
@@ -1349,7 +1396,13 @@ The most-used env knobs (full list in `threadkeeper/config.py`):
|
|
|
1349
1396
|
| `THREADKEEPER_PROBE_RESULT_RETENTION_DAYS` | 0 | prune old `probe_results` and refresh reliability aggregates; 0 keeps forever |
|
|
1350
1397
|
| `THREADKEEPER_RETENTION_WAL_CHECKPOINT` | false | run `PRAGMA wal_checkpoint(TRUNCATE)` during retention passes |
|
|
1351
1398
|
| `THREADKEEPER_RETENTION_VACUUM_AFTER_ROWS` | 0 | run `VACUUM` after a pass deletes at least this many rows; 0 disables VACUUM |
|
|
1399
|
+
| `THREADKEEPER_WORKFLOW_RETENTION_DAYS` | 30 | age protection for terminal Curator passes and consumed Evolve research handoffs; `0` disables the age bound |
|
|
1400
|
+
| `THREADKEEPER_WORKFLOW_RETENTION_COUNT` | 100 | newest terminal Curator passes and research handoffs protected by count; `0` disables the count bound |
|
|
1352
1401
|
| `THREADKEEPER_MEMORY_EGRESS` | `all` | cross-provider scope for personal-class memory (verbatim quotes + dialectic user-model) in `brief()`. `all` = current behavior, egress to whichever vendor backs the consuming CLI. `same-vendor` = personal renders only for Claude/Anthropic, omitted for OpenAI/Google/Microsoft CLIs. `work-only` = personal never rendered, any vendor. See [Memory egress](#memory-egress-cross-provider-privacy) |
|
|
1402
|
+
| `THREADKEEPER_OTEL_ENABLED` | false | enable privacy-safe OTLP tracing only when an endpoint is also configured |
|
|
1403
|
+
| `THREADKEEPER_OTEL_ENDPOINT` | "" | OTLP/HTTP collector trace endpoint, normally `https://collector.example/v1/traces` |
|
|
1404
|
+
| `THREADKEEPER_OTEL_EXPORT_TIMEOUT_S` | 2 | collector request timeout; export happens outside the local workflow |
|
|
1405
|
+
| `THREADKEEPER_OTEL_EXPORT_QUEUE_SIZE` | 256 | bounded per-process span queue (1–2048); oldest queued spans are dropped under pressure |
|
|
1353
1406
|
| `THREADKEEPER_AUTO_REVIEW` | "" (off) | auto-review on `close_thread` |
|
|
1354
1407
|
| `THREADKEEPER_AUTO_UPDATE_INTERVAL_S` | 86400 | MCP self-update check interval; 0 disables |
|
|
1355
1408
|
| `THREADKEEPER_AUTO_UPDATE_RESTART` | "1" | exit MCP process after an update passes setup/import smoke checks so the host restarts on new code |
|
|
@@ -1383,7 +1436,7 @@ The most-used env knobs (full list in `threadkeeper/config.py`):
|
|
|
1383
1436
|
| `THREADKEEPER_CURATOR_INTERVAL_S` | 259200 | deep curator audit every three days; set `0` to disable |
|
|
1384
1437
|
| `THREADKEEPER_CURATOR_MANAGE_FOREGROUND_SKILLS` | 0 | allow snapshot-scoped Curator repair/merge/delete of foreground skills; pinned/untracked skills remain protected |
|
|
1385
1438
|
| `THREADKEEPER_CURATOR_MIN_LESSONS` | 3 | min lessons before curator engages |
|
|
1386
|
-
| `THREADKEEPER_CURATOR_WEB_RESEARCH` | `
|
|
1439
|
+
| `THREADKEEPER_CURATOR_WEB_RESEARCH` | `0` (off) | explicit consent for the isolated Curator web researcher; it receives only fixed public compatibility queries, while foreground/private/unclassified entries use `HUMAN_REVIEW` |
|
|
1387
1440
|
| `THREADKEEPER_CURATOR_DESTRUCTIVE` | `1` (on) | curator child writes its REPORT then applies its own PATCH/PRUNE/CONSOLIDATE directly (incl. `lesson_remove` for prune/consolidate); set `0` for advisory REPORT-only. `[PROTECTED]` entries are refused server-side |
|
|
1388
1441
|
| `THREADKEEPER_CURATOR_MAX_DESTRUCTIVE_PER_PASS` | 10 | shared server-side ceiling for one destructive Curator pass across `lesson_remove` and `skill_manage(action='delete')`; `0` disables autonomous deletes and foreground deletes bypass it |
|
|
1389
1442
|
| `THREADKEEPER_CURATOR_SNAPSHOT_RETENTION` | 10 | number of destructive curator pre-mutation snapshots to retain under `<reports_dir>/snapshots`; current pass is always retained |
|
|
@@ -1433,6 +1486,7 @@ The most-used env knobs (full list in `threadkeeper/config.py`):
|
|
|
1433
1486
|
| `THREADKEEPER_EVOLVE_REVIEW_INTERVAL_S` | 0 (off) | evolve-reviewer daemon tick (s); audits thread-keeper for safety/leaks/optimization/new ideas, updates roadmap/issues, and includes legacy evolve suggestions as input. Runs as two alternating phases — read-only web research, then a privileged web-free audit that consumes the fenced research digest (#79) — so a full cycle spans two ticks |
|
|
1434
1487
|
| `THREADKEEPER_EVOLVE_REVIEW_BACKLOG_MAX` | 25 | max open, not-yet-applied `roadmap`-label issues before the issue-creating audit is skipped and records `backlog_saturated`; skip-labelled and untrusted-author roadmap issues still count; `0` disables the cap |
|
|
1435
1488
|
| `THREADKEEPER_EVOLVE_APPLY_INTERVAL_S` | 0 (off) | evolve-applier daemon tick (s); implements one open GitHub issue at a time, then falls back to Curator reports and promoted legacy evolve suggestions. Empty checks are throttled between intervals; actionable work and manual apply tools still dispatch |
|
|
1489
|
+
| `THREADKEEPER_EVOLVE_AUTOLAND` | true | land open non-draft PRs authored by the account `gh` acts as: squash-merge one once GitHub reports it up to date with required checks green, and update one that fell behind the base. Other accounts' PRs are never touched. `0`/`false` leaves every merge to a human |
|
|
1436
1490
|
| `THREADKEEPER_EVOLVE_REPO_ROOT` | (auto) | absolute path to the thread-keeper git checkout the evolve reviewer/applier branch, test, and open PRs against. When empty, the repo is resolved automatically: the package's parent dir for an editable `install.sh`, else a managed checkout under the DB dir that is auto-cloned on first use. Set this to pin an explicit checkout |
|
|
1437
1491
|
| `THREADKEEPER_EVOLVE_AUTO_CLONE` | true | auto-provision a managed checkout that runs remote `pip install -e` and tests; set `0`/`false` on shared or multi-user hosts unless that remote-code-execution boundary is explicitly accepted |
|
|
1438
1492
|
| `THREADKEEPER_EVOLVE_REPO_URL` | upstream repo | HTTPS `github.com` source for the managed clone; restart-only, and other hosts/schemes are refused |
|
|
@@ -1562,6 +1616,38 @@ Three tools keep the memory tidy. `consolidate()` and `forget()` default to
|
|
|
1562
1616
|
|
|
1563
1617
|
## Telemetry
|
|
1564
1618
|
|
|
1619
|
+
### Privacy-safe OTLP traces
|
|
1620
|
+
|
|
1621
|
+
OTLP export is **off by default**. To opt in, set both
|
|
1622
|
+
`THREADKEEPER_OTEL_ENABLED=1` and `THREADKEEPER_OTEL_ENDPOINT` to an
|
|
1623
|
+
OTLP/HTTP `/v1/traces` endpoint. ThreadKeeper sends OTLP JSON asynchronously;
|
|
1624
|
+
collector failure, timeout, or a full queue never delays a local MCP call,
|
|
1625
|
+
spawn, watchdog action, or SQLite write.
|
|
1626
|
+
|
|
1627
|
+
One spawned workflow is linked as `MCP spawn → workflow → agent → child MCP
|
|
1628
|
+
operation`. The W3C trace context is saved with the task and passed only in the
|
|
1629
|
+
private child environment (and its slim MCP config), never in a prompt or CLI
|
|
1630
|
+
argument. A watchdog continuation uses the prior agent span as its parent, so
|
|
1631
|
+
retries remain in the same trace.
|
|
1632
|
+
|
|
1633
|
+
The exporter has a fixed allowlist: operation/tool identifier, latency and
|
|
1634
|
+
queue wait, provider/model identifiers, input/output/total tokens, USD cost,
|
|
1635
|
+
retry count, and terminal outcome. Operation names are fixed; tool/provider
|
|
1636
|
+
identifiers are limited to 64 safe characters, model identifiers to 96, and a
|
|
1637
|
+
process exports at most 64 distinct model values (later values become
|
|
1638
|
+
`unknown`).
|
|
1639
|
+
Everything else is excluded by construction: prompts, MCP arguments/results,
|
|
1640
|
+
memory bodies, user quotes, credentials, paths, task logs, and SQLite event
|
|
1641
|
+
summaries are never span attributes.
|
|
1642
|
+
|
|
1643
|
+
The local SQLite event ledger remains the source of truth. It retains only the
|
|
1644
|
+
opaque trace linkage beside a task row, so its existing task-retention policy
|
|
1645
|
+
also removes that linkage. Configure collector retention at the collector; no
|
|
1646
|
+
trace payload is persisted locally. If traces do not arrive, first verify the
|
|
1647
|
+
endpoint includes `/v1/traces`; then inspect collector connectivity. A full
|
|
1648
|
+
queue intentionally drops its oldest pending spans rather than growing memory
|
|
1649
|
+
or blocking the workflow.
|
|
1650
|
+
|
|
1565
1651
|
- **`mp_dashboard(window_days=7)`** — one-call rollup of the whole
|
|
1566
1652
|
system, read-only. Three sections: **stores** (threads by state,
|
|
1567
1653
|
notes/dialog/distill/concepts counts, skills + claims by tier,
|
|
@@ -1702,6 +1788,19 @@ the high-volume tables (`dialog_messages`, `dialog_fts`, `dialog_vec`,
|
|
|
1702
1788
|
`signals`, `events`, `tasks`, `probe_results`) so growth is visible before it
|
|
1703
1789
|
becomes a problem.
|
|
1704
1790
|
|
|
1791
|
+
Terminal Curator passes own their frozen batch text, `REPORT-*`, `AUDIT-*`, and
|
|
1792
|
+
destructive snapshot; Evolve handoffs own their `RESEARCH-*` digest. The
|
|
1793
|
+
retention daemon keeps active/retryable work, recovery material, and endorsed
|
|
1794
|
+
but unapplied reports. After both enabled workflow bounds expire, it first
|
|
1795
|
+
compacts batch/research bodies to a SHA-256 plus a 512-character summary and
|
|
1796
|
+
removes only owned files. A later pass removes the compacted rows. File removal
|
|
1797
|
+
is path-contained to the configured Curator or Evolve directory, rejects
|
|
1798
|
+
symlinks, and is journaled so an interrupted delete retries safely. Use
|
|
1799
|
+
`workflow_retention_preview()` for the dry-run counts/bytes and oldest terminal
|
|
1800
|
+
pass; `mp_dashboard()` shows its latest outcome. A selective `forget()` that
|
|
1801
|
+
matches a frozen workflow body compacts it immediately, including active work;
|
|
1802
|
+
the normal report/lesson review guidance still applies to generalized content.
|
|
1803
|
+
|
|
1705
1804
|
`db_compact()` is the opt-in disk-reclaim tool: `VACUUM` + a mandatory
|
|
1706
1805
|
`dialog_fts` rebuild (schema v2 keys the FTS index on `dialog_messages`
|
|
1707
1806
|
rowids, which `VACUUM` is permitted to renumber — the rebuild is what
|
|
@@ -1868,9 +1967,9 @@ reusable verdict logic lives in `threadkeeper/verify_ingest.py`.
|
|
|
1868
1967
|
## Memory-quality evaluation
|
|
1869
1968
|
|
|
1870
1969
|
The ingest verifier above answers *"did we capture the data?"*. The
|
|
1871
|
-
memory-quality harness answers
|
|
1872
|
-
|
|
1873
|
-
|
|
1970
|
+
memory-quality harness answers two separate questions: *"did we retrieve the
|
|
1971
|
+
right evidence?"* and *"does an agent produce the right final answer from
|
|
1972
|
+
that evidence?"* It's modeled on
|
|
1874
1973
|
[LongMemEval](https://arxiv.org/pdf/2410.10813) (ICLR 2025) plus mem0's 2026
|
|
1875
1974
|
[tokens-per-retrieval](https://mem0.ai/blog/ai-memory-benchmarks-in-2026)
|
|
1876
1975
|
cost axis, and runs the **real** `search()` / `dialog_search()` / `brief()`
|
|
@@ -1881,24 +1980,34 @@ python scripts/memory_eval/run.py # bundled demo corpus, lexical
|
|
|
1881
1980
|
python scripts/memory_eval/run.py --json # machine-readable report
|
|
1882
1981
|
python scripts/memory_eval/run.py --db snap.sqlite --ground-truth my_labels.json
|
|
1883
1982
|
python scripts/memory_eval/run.py --semantic # use embeddings if installed
|
|
1884
|
-
python scripts/memory_eval/run.py --
|
|
1983
|
+
python scripts/memory_eval/run.py --matrix --strict # FTS/hybrid migration gate
|
|
1984
|
+
age -d holdout.json.age | python scripts/memory_eval/run.py \
|
|
1985
|
+
--ground-truth /dev/stdin --private-holdout # no per-case output
|
|
1885
1986
|
```
|
|
1886
1987
|
|
|
1887
|
-
It reports
|
|
1988
|
+
It reports these headline groups over a fixed ground-truth set:
|
|
1888
1989
|
|
|
1889
|
-
- **
|
|
1890
|
-
|
|
1891
|
-
|
|
1990
|
+
- **evidence recall** and **final-answer correctness** — separate scores, both
|
|
1991
|
+
per axis. The final answer comes from a deterministic replay responder that
|
|
1992
|
+
may emit only facts found in the returned context; it gives CI a stable
|
|
1993
|
+
boundary between retrieval and reasoning failures.
|
|
1892
1994
|
- **abstention rate** — of the *never-happened* questions, the fraction the
|
|
1893
|
-
system correctly refused.
|
|
1894
|
-
|
|
1895
|
-
stale facts.
|
|
1995
|
+
system correctly refused. Retention/curation removals and egress-blocked
|
|
1996
|
+
personal memory are also required to end in a refusal.
|
|
1896
1997
|
- **tokens-per-retrieval** — mean / median / max tokens of what each query
|
|
1897
|
-
returned,
|
|
1898
|
-
recalls more also costs more).
|
|
1998
|
+
returned, plus equivalent final-answer token totals.
|
|
1899
1999
|
- **retrieval latency** — mean / p50 / p95 / max wall-clock milliseconds. With
|
|
1900
2000
|
`--semantic`, the backend is reported as `hybrid`, because dense candidates
|
|
1901
2001
|
augment rather than replace FTS.
|
|
2002
|
+
- **outcome classification** — retrieval failure, reasoning failure,
|
|
2003
|
+
stale-memory use, removed-memory use, and privacy-policy violation.
|
|
2004
|
+
|
|
2005
|
+
`--matrix` runs every public-fixture case through the FTS and hybrid backends,
|
|
2006
|
+
three fixture states (`baseline`, `retained`, `curated`), and every personal
|
|
2007
|
+
memory egress policy (`all`, `same-vendor`, `work-only`). A hybrid row is marked
|
|
2008
|
+
unavailable when the optional semantic extra is not installed. `--strict`
|
|
2009
|
+
requires the versioned fixture thresholds and zero safety violations, making
|
|
2010
|
+
the same command suitable for retrieval/model migration gates.
|
|
1902
2011
|
|
|
1903
2012
|
For DB concurrency, run the reproducible local gate:
|
|
1904
2013
|
|
|
@@ -1910,18 +2019,20 @@ The JSON result includes expected/actual writes, throughput, p50/p95/p99/max
|
|
|
1910
2019
|
write latency, worker errors, elapsed time, and `PRAGMA quick_check`; a non-zero
|
|
1911
2020
|
exit means a lost write, worker failure, or integrity failure.
|
|
1912
2021
|
|
|
1913
|
-
With no `--db` the harness builds the bundled
|
|
1914
|
-
(`scripts/memory_eval/ground_truth.json` — a fictional "billing
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
2022
|
+
With no `--db` the harness builds the bundled, versioned public synthetic
|
|
2023
|
+
fixture (`scripts/memory_eval/ground_truth.json` — a fictional "billing
|
|
2024
|
+
service") into a throwaway DB. Bump its `version` whenever cases, labels, or
|
|
2025
|
+
thresholds change; CI uses the checked-in version and its stable thresholds.
|
|
2026
|
+
`--db` runs **read-only**: the snapshot is copied to a temp file and the
|
|
2027
|
+
original is never opened for writing.
|
|
2028
|
+
|
|
2029
|
+
For a private holdout, keep the corpus encrypted or outside the repository and
|
|
2030
|
+
pass it with `--private-holdout`. The runner does not decrypt data itself; it
|
|
2031
|
+
accepts a locally decrypted file or stdin and deletes its temporary DB on exit.
|
|
2032
|
+
Private mode emits aggregate metrics only — no case rows, failure details,
|
|
2033
|
+
retrieved context, or replayed answer is written to stdout, artifacts, or the
|
|
2034
|
+
repository. See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the corpus
|
|
2035
|
+
contract and migration-gate interpretation.
|
|
1925
2036
|
|
|
1926
2037
|
## Evaluating learning-loop decision quality
|
|
1927
2038
|
|
|
@@ -2023,7 +2134,9 @@ threadkeeper/
|
|
|
2023
2134
|
so `tools/list` carries MCP 2025-06-18 `ToolAnnotations` for every
|
|
2024
2135
|
registered tool: `readOnlyHint=True` for pure reads (`brief`, `context`, `search`,
|
|
2025
2136
|
`dialog_search`, the status tools, …) and `readOnlyHint=False`
|
|
2026
|
-
for mutations.
|
|
2137
|
+
for mutations. Advertised reads use query-only database connections and never
|
|
2138
|
+
bootstrap a session, start daemon work, refresh process data, or mutate
|
|
2139
|
+
lifecycle state. `lesson_list` / `lesson_get` are classified as non-destructive
|
|
2027
2140
|
writes because they bump lesson access counters. Delete/overwrite/kill tools
|
|
2028
2141
|
carry `destructiveHint=True` (`compost` is read-only — it only surfaces idle
|
|
2029
2142
|
threads). A confirmation/elicitation host reads this to decide which calls
|
|
@@ -2038,6 +2151,15 @@ capability before prompting, uses only a flat primitive schema, and leaves
|
|
|
2038
2151
|
unsupported clients on the existing text/tool fallback path. The first protected
|
|
2039
2152
|
write is `dialectic_supersede`.
|
|
2040
2153
|
|
|
2154
|
+
**Protocol compatibility (#344).** The stdio server supports the
|
|
2155
|
+
`2025-11-25` initialize-handshake era and the `2026-07-28` request-envelope
|
|
2156
|
+
era. Legacy hosts retain the existing tools, resources, and prompts. Modern
|
|
2157
|
+
calls derive identity and capabilities from every request, static discovery
|
|
2158
|
+
catalogs advertise public cache freshness, and replaying a completed write with
|
|
2159
|
+
the same caller-bound JSON-RPC id returns the original result instead of
|
|
2160
|
+
committing a second mutation. Sealed continuation state expires after five
|
|
2161
|
+
minutes; an interrupted write with no terminal result is rejected on replay.
|
|
2162
|
+
|
|
2041
2163
|
Detailed map in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
|
|
2042
2164
|
Open work in [docs/ROADMAP.md](docs/ROADMAP.md) and the
|
|
2043
2165
|
[Issues tab](https://github.com/po4erk91/thread-keeper/issues).
|