threadkeeper 0.22.0__tar.gz → 0.23.0__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.22.0/threadkeeper.egg-info → threadkeeper-0.23.0}/PKG-INFO +354 -50
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/README.md +353 -49
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/pyproject.toml +3 -1
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_agent_status.py +1 -0
- threadkeeper-0.23.0/tests/test_child_memory_access.py +252 -0
- threadkeeper-0.23.0/tests/test_consequential_state.py +216 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_curator.py +323 -4
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_db_schema.py +8 -0
- threadkeeper-0.23.0/tests/test_evidence_resources.py +295 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_evolve_applier.py +448 -6
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_host_env.py +38 -2
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_host_wedged.py +3 -2
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_hybrid_retrieval.py +2 -2
- threadkeeper-0.23.0/tests/test_lesson_freshness.py +254 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_lessons.py +8 -3
- threadkeeper-0.23.0/tests/test_mcp_conformance_gate.py +45 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_mcp_protocol_conformance.py +68 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_menubar_app.py +59 -2
- threadkeeper-0.23.0/tests/test_model_pricing.py +158 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_model_router.py +59 -1
- threadkeeper-0.23.0/tests/test_model_router_digest.py +330 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_notify_daemon.py +41 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_project_scope.py +4 -1
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_review_prompts.py +4 -2
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_search_fts_punctuation.py +4 -1
- threadkeeper-0.23.0/tests/test_semantic_bundle.py +217 -0
- threadkeeper-0.23.0/tests/test_skill_fixtures.py +280 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_skills.py +358 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_spawn_child_env.py +68 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_spawn_slim.py +33 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_spawn_worktree_isolation.py +26 -0
- threadkeeper-0.23.0/tests/test_task_gate.py +190 -0
- threadkeeper-0.23.0/tests/test_task_worktree_retention.py +353 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_tool_annotations.py +6 -4
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_tool_profiles.py +23 -1
- threadkeeper-0.23.0/tests/test_tracing.py +470 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/_mcp.py +13 -3
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/_setup.py +4 -6
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/adapters/base.py +2 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/adapters/claude_code.py +3 -4
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/adapters/codex.py +1 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/agent_status.py +4 -2
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/assets/macos-agent-status/README.md +14 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/assets/macos-agent-status/ThreadKeeperAgentStatus.swift +116 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/authority.py +26 -1
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/brief.py +2 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/candidate_reviewer.py +2 -1
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/config.py +3 -0
- threadkeeper-0.23.0/threadkeeper/conformance_server.py +31 -0
- threadkeeper-0.23.0/threadkeeper/consequential_state.py +158 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/curator.py +238 -19
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/curator_snapshots.py +13 -4
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/db.py +130 -2
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/dialectic_validator.py +1 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/embeddings.py +25 -9
- threadkeeper-0.23.0/threadkeeper/evidence.py +238 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/evolve_applier.py +590 -105
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/evolve_daemon.py +3 -2
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/host.py +13 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/ingest.py +1 -1
- threadkeeper-0.23.0/threadkeeper/lesson_freshness.py +138 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/lessons.py +21 -6
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/mcp_skills.py +14 -0
- threadkeeper-0.23.0/threadkeeper/memory_access.py +275 -0
- threadkeeper-0.23.0/threadkeeper/model_pricing.py +203 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/model_router.py +78 -17
- threadkeeper-0.23.0/threadkeeper/model_router_digest.py +379 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/notify.py +37 -8
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/probe_daemon.py +1 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/project_scope.py +19 -1
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/protocol.py +24 -6
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/retrieval.py +4 -2
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/review_prompts.py +10 -2
- threadkeeper-0.23.0/threadkeeper/semantic_bundle.py +1127 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/server.py +1 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/shadow_review.py +2 -1
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/skill_audit.py +327 -20
- threadkeeper-0.23.0/threadkeeper/skill_lifecycle.py +18 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/skill_watcher.py +17 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/spawn_budget.py +3 -0
- threadkeeper-0.23.0/threadkeeper/task_worktrees.py +283 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tool_profiles.py +9 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tool_schemas.py +31 -5
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/consolidate.py +46 -5
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/curator.py +63 -4
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/dashboard.py +2 -1
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/dialog.py +26 -12
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/evolve_applier.py +21 -3
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/lessons.py +61 -4
- threadkeeper-0.23.0/threadkeeper/tools/memory_proposals.py +80 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/panel.py +1 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/pickup.py +1 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/resources.py +2 -3
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/skills.py +582 -93
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/spawn.py +123 -13
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/threads.py +13 -6
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tracing.py +134 -6
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/trash.py +30 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/workflow_artifacts.py +5 -1
- {threadkeeper-0.22.0 → threadkeeper-0.23.0/threadkeeper.egg-info}/PKG-INFO +354 -50
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper.egg-info/SOURCES.txt +20 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper.egg-info/entry_points.txt +1 -0
- threadkeeper-0.22.0/tests/test_model_router_digest.py +0 -107
- threadkeeper-0.22.0/tests/test_tracing.py +0 -237
- threadkeeper-0.22.0/threadkeeper/model_router_digest.py +0 -234
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/LICENSE +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/setup.cfg +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_action_outcomes.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_adapters.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_antigravity_ingest.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_auto_update.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_backup.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_brief_footprint.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_brief_hook_size.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_brief_sections.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_candidate_reviewer.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_ci_parallel.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_concepts.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_config_settings.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_config_watcher.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_core_memory.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_daemon_host_config.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_daemon_host_integration.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_daemon_liveness.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_daemon_state.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_dashboard.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_dashboard_app.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_db_compact.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_db_contention.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_db_leak_guard.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_db_migration_fts.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_db_runtime.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_delegated_search.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_dialectic.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_dialectic_drift_eval.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_dialectic_feed_tools.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_dialectic_miner.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_dialectic_observation_resolve.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_dialectic_recompute.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_dialectic_tier.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_dialectic_validator.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_dialog_fts_external.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_documentation_inventory.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_egress_policy.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_embed_routing.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_embedding_generation.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_embedding_model_revision.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_embedding_storage_dedup.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_error_paths.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_eval_harness.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_evolve_apply_2.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_evolve_apply_3.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_evolve_apply_43.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_evolve_apply_45.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_evolve_apply_48.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_evolve_daemon.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_extract_daemon.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_extract_dedup.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_forget.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_github_budget.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_github_safety.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_helpers.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_hook_child_guard.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_host_embed.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_host_main.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_i18n_multilang.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_identity.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_ingest_cursor.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_ingest_denylist.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_ingest_secret_redaction.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_ingest_status.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_ingest_transactions.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_lesson_index.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_lesson_violations.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_mcp_resources_prompts.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_mcp_sdk_compat.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_mcp_server_instructions.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_mcp_skills_extension.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_mcp_tasks.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_memory_authority_lifecycle.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_memory_compatibility.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_memory_eval.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_memory_guard.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_memory_guard_host.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_missed_spawns.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_model_catalog.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_model_router_tools.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_model_routes.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_nudges.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_onnx_embeddings.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_panel.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_permissions.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_pickup.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_probe_daemon.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_process_health.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_release_workflows.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_retention.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_session_read_purity.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_setup.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_shadow_review.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_single_flight_prompt_prefixes.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_skill_hint.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_skill_passive_tier.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_skill_tier.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_skill_updater.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_skill_use_parser.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_skill_watcher.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_spawn_background_cwd.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_spawn_budget.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_spawn_codex_stdin.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_spawn_config.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_spawn_hint.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_spawn_permission_gate.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_spawn_reap.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_spawn_result.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_spawn_watchdog.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_spawn_wrap.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_storage.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_sync_capture.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_sync_identity.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_sync_migrate.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_sync_protocol.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_sync_reset_node.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_sync_transport.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_task_retention.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_task_spool.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_thin_session.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_thread_janitor.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_threads.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_tools_smoke.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_validate_threads.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_vec_search.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_verify_ingest.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/tests/test_workflow_retention.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/__init__.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/_spawn_wrap.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/action_outcomes.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/adapters/__init__.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/adapters/_hook_helpers.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/adapters/antigravity.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/adapters/claude_desktop.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/adapters/copilot.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/adapters/vscode.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/agent_metadata.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/assets/macos-agent-status/Info.plist +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/assets/macos-agent-status/build.sh +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/assets/macos-agent-status/install.sh +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/auto_update.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/backup.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/config_io.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/config_watcher.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/daemon_liveness.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/daemon_state.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/daemon_supervisor.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/dashboard_app.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/dialectic_drift_eval.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/dialectic_miner.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/egress.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/elicitation.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/eval/__init__.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/eval/__main__.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/eval/harness.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/extract_daemon.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/forget.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/github_budget.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/github_safety.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/harvest.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/helpers.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/host_embed.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/i18n.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/identity.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/instructions.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/lesson_violations.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/link_health.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/mcp_tasks.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/memory_compat.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/memory_guard.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/menubar_app.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/migrate_embeddings.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/model_catalog.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/model_routes.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/nudges.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/permissions.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/process_health.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/read_context.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/retention.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/search_proxy.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/skill_updater.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/spawn_config.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/spawn_result.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/storage.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/sync/__init__.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/sync/capture.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/sync/daemon.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/sync/identity.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/sync/migrate.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/sync/protocol.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/sync/reset_node.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/sync/server.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/task_spool.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/thread_janitor.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/__init__.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/agent_status.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/authority.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/candidate_reviewer.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/capabilities.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/concepts.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/config_watch.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/core_memory.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/correlation.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/db_maintenance.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/dialectic.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/dialectic_feed.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/distill.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/evolve_research.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/extract.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/forget.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/graph.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/invariants.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/memory_guard.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/missed_spawns.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/model_router.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/peers.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/probes.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/process_health.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/project_scope.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/prompts.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/session.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/shadow_review.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/style.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/sync.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/tools/validate.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/verify_ingest.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper/wikilinks.py +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper.egg-info/dependency_links.txt +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/threadkeeper.egg-info/requires.txt +0 -0
- {threadkeeper-0.22.0 → threadkeeper-0.23.0}/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.
|
|
3
|
+
Version: 0.23.0
|
|
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
|
|
@@ -101,7 +101,11 @@ make it more than a memory store:
|
|
|
101
101
|
`~/.codex/skills/`, `~/.gemini/config/skills/` for Antigravity,
|
|
102
102
|
existing `~/.agents/skills/`, extra roots from
|
|
103
103
|
`THREADKEEPER_EXTRA_SKILLS_DIRS`, and `~/.threadkeeper/skills/`), with
|
|
104
|
-
lessons.md as a fallback for CLIs without a native skills loader.
|
|
104
|
+
lessons.md as a fallback for CLIs without a native skills loader. A managed
|
|
105
|
+
skill write reports success only after every mirror has the expected file
|
|
106
|
+
set and hashes; `ERR mirror_partial_failure` keeps the canonical copy and
|
|
107
|
+
names only the affected consumer plus relative file. Retry safely with
|
|
108
|
+
`skill_manage(action="reconcile", name="<skill>")`.
|
|
105
109
|
|
|
106
110
|
Foreground MCP servers also run a daily self-update check by default. Source
|
|
107
111
|
checkouts fast-forward their tracked git branch and reinstall the editable
|
|
@@ -254,6 +258,22 @@ surface memory as attachable / `@`-mentionable context through a mechanical
|
|
|
254
258
|
channel. The brief resource renders lean and agent-status uses a cached snapshot,
|
|
255
259
|
so an automatic host pull is **side-effect-free**.
|
|
256
260
|
|
|
261
|
+
`search` and `dialog_search` also return structured hits and `resource_link`
|
|
262
|
+
blocks. Read a hit's `resource_uri` with `resources/read` to inspect its evidence
|
|
263
|
+
without a broader search. Notes can also provide a `thread_uri` for a bounded
|
|
264
|
+
thread excerpt. Dialog links contain the matching message and up to two messages
|
|
265
|
+
on each side from the same source, session, and scope. Windows have fixed
|
|
266
|
+
membership; later messages do not expand an issued link.
|
|
267
|
+
|
|
268
|
+
These opaque `memory://evidence/...` links are private to the requesting caller
|
|
269
|
+
and project, expire after five minutes, and may be evicted sooner or lost on
|
|
270
|
+
server restart. Search again for a fresh link. Evidence reads return at most
|
|
271
|
+
32 KiB of JSON, mark shortened bodies with `truncated`, and recheck scope,
|
|
272
|
+
authority invalidation, erasure, and dialog retention on every read. Thread
|
|
273
|
+
excerpts include at most ten notes. Links are not listed in `resources/list`
|
|
274
|
+
and must not be cached. Hosts that ignore links and structured output keep the
|
|
275
|
+
same first text block and search behavior.
|
|
276
|
+
|
|
257
277
|
**Prompts** turn the curation / audit / review flows into discoverable,
|
|
258
278
|
parameterized commands; each just drives the existing tools.
|
|
259
279
|
|
|
@@ -400,6 +420,27 @@ sent to another model provider.
|
|
|
400
420
|
|
|
401
421
|
### Spawn — primary parallelism primitive
|
|
402
422
|
|
|
423
|
+
Public children have explicit durable-memory access. `spawn(...,
|
|
424
|
+
memory_access="read_only")` is the default; `memory_access="propose"` queues
|
|
425
|
+
supported memory-writing calls as pending candidates. A foreground reviewer
|
|
426
|
+
uses `memory_proposals()` and `memory_proposal_decide(id, accept=True)` to
|
|
427
|
+
apply one candidate. New generated artifacts keep **observed** authority.
|
|
428
|
+
Only private Curator and Evolve launchers can grant direct `write` access.
|
|
429
|
+
Curator researchers, probe runners, model routers, and general helpers remain
|
|
430
|
+
read-only; learning reviewers submit proposals. Coordination and authorized
|
|
431
|
+
research/report handoffs remain available.
|
|
432
|
+
|
|
433
|
+
These are three separate controls: tool profiles decide which tools a child
|
|
434
|
+
can discover; provenance labels describe where content came from; a persisted,
|
|
435
|
+
task-bound memory capability decides whether it can write accepted memory.
|
|
436
|
+
Changing `write_origin`, a role, or the advertised tool profile grants no memory
|
|
437
|
+
authority. An omitted or forged child grant fails closed. Ordinary child reads
|
|
438
|
+
are capped to the launch project's namespace plus global/shared memory, even
|
|
439
|
+
with `cross_project=True`; a child outside a resolved project sees only
|
|
440
|
+
global/shared memory. Existing memory keeps its current scope. This boundary protects server
|
|
441
|
+
tools and storage helpers; it does not sandbox arbitrary code running under
|
|
442
|
+
the same operating-system account with direct access to database files.
|
|
443
|
+
|
|
403
444
|
`spawn(prompt, slim=True, role=..., visible=False, ...)` launches a child
|
|
404
445
|
Claude session via a `claude -p` subprocess. By default `slim=True`: the
|
|
405
446
|
child loads only the thread-keeper MCP, no embeddings, no third-party
|
|
@@ -671,6 +712,36 @@ optional `THREADKEEPER_EXTRA_SKILLS_DIRS`, plus the canonical
|
|
|
671
712
|
CLI-agnostic fallback for clients without a native skills loader (Copilot and
|
|
672
713
|
bare MCP clients).
|
|
673
714
|
|
|
715
|
+
**Hidden test fixtures.** Maintainers can keep seeds and probes without adding
|
|
716
|
+
them to the guidance that agents discover or to Curator's production health
|
|
717
|
+
totals. Create one with
|
|
718
|
+
`skill_manage(action="create", name="validator-example", description="Validation only", content="...", classification="fixture")`.
|
|
719
|
+
Fixtures live beside each skill root under
|
|
720
|
+
`<root parent>/.threadkeeper-fixtures/<root name>/<name>/`, outside recursive
|
|
721
|
+
skill discovery. The durable
|
|
722
|
+
classification is separate from the active/stale/archived aging state;
|
|
723
|
+
fixtures never age automatically.
|
|
724
|
+
|
|
725
|
+
Use `skill_list(include_fixtures=True)` to list them and
|
|
726
|
+
`skill_validate(name="validator-example", include_fixtures=True)` to run the
|
|
727
|
+
usual file, link, consumer, and mirror checks. Dedicated test runs can record
|
|
728
|
+
their own counters with `skill_record(..., include_fixtures=True)`; passive
|
|
729
|
+
usage and ordinary production totals exclude fixtures. Retire a fixture with
|
|
730
|
+
`skill_manage(action="delete", name="validator-example", force=True)` from a
|
|
731
|
+
foreground session. The usual protection and trash/restore rules still apply.
|
|
732
|
+
Semantic bundle export/import and hidden mirror copies preserve classification.
|
|
733
|
+
|
|
734
|
+
For a legacy fixture, first select the entry using known test provenance and
|
|
735
|
+
call `skill_fixture_migrate(name="...", evidence="why this is validation data")`.
|
|
736
|
+
This preview returns the candidate's current classification, origin, evidence,
|
|
737
|
+
and SHA-256 without changing it. After reviewing that evidence, call it again
|
|
738
|
+
with `dry_run=False` and `expected_sha256="<preview sha256>"` from a foreground
|
|
739
|
+
session. It moves the entry into hidden storage and removes ordinary mirror
|
|
740
|
+
copies. Retry partial mirror failures with `skill_manage(action="reconcile", name="...")`.
|
|
741
|
+
Names such as `test-*`, `seed-*`, or `probe-*` never trigger classification.
|
|
742
|
+
Existing and user-authored guidance stays production guidance until an explicit
|
|
743
|
+
maintainer migration; startup performs no fixture data migration.
|
|
744
|
+
|
|
674
745
|
**Harvest boundary (issue #36).** The dialog-reading loops share
|
|
675
746
|
`threadkeeper.harvest` as their session exclusion boundary. Raw transcripts are
|
|
676
747
|
still persisted for diagnostics, but shadow-review, extract, dialectic mining,
|
|
@@ -697,6 +768,33 @@ them without touching foreground-authored ones, and a write-time screen
|
|
|
697
768
|
refuses loop-origin lesson/skill bodies that contain imperative-override /
|
|
698
769
|
remote-exec idioms. See [`SECURITY.md`](SECURITY.md).
|
|
699
770
|
|
|
771
|
+
**Host settings need consent and rollback (#390).** Background writers cannot
|
|
772
|
+
save unconditional advice to reset a host proxy, remove credentials, change
|
|
773
|
+
shell/global settings, control startup services, change home/system permissions,
|
|
774
|
+
or alter global packages. Each procedure must state a narrow confirmed
|
|
775
|
+
precondition, require the owner's consent, save the original state, and restore
|
|
776
|
+
it during cleanup, including on failure. Read-only checks and project-local
|
|
777
|
+
changes remain allowed. This is a conservative English text/command screen,
|
|
778
|
+
separate from injection detection, rather than a semantic safety guarantee.
|
|
779
|
+
|
|
780
|
+
Existing unsafe advice stays on disk with an **OWNER REVIEW REQUIRED** warning
|
|
781
|
+
in lesson retrieval, skill listings, and Curator inventories. Skill manifests
|
|
782
|
+
show the warning in their description; MCP resource delivery pauses with the
|
|
783
|
+
same warning. Curator never rewrites protected records to clear it, including
|
|
784
|
+
in its verifier phase. The skill watcher also flags direct file edits.
|
|
785
|
+
|
|
786
|
+
To clear a warning, the owner reviews the procedure in a foreground session,
|
|
787
|
+
then uses `lesson_patch` / `lesson_append` or `skill_manage` to remove the unsafe
|
|
788
|
+
advice or add all three guards. For example: “Only when inspection has confirmed
|
|
789
|
+
an observed test-owned proxy left by this test, ask the user for explicit consent
|
|
790
|
+
before changing it. Save the original proxy settings, reset the proxy for the
|
|
791
|
+
test, and restore the original settings in cleanup even if the test fails.” Keep
|
|
792
|
+
the condition and guards together in each procedure paragraph. Retrieval checks
|
|
793
|
+
the current content, so the warning clears after a safe repair; there is no
|
|
794
|
+
blanket approval switch. Historical `host_state_review` telemetry keeps only
|
|
795
|
+
fixed categories and a SHA-256 fingerprint, without host values, paths, titles,
|
|
796
|
+
or command text.
|
|
797
|
+
|
|
700
798
|
#### 1. Auto-review on close_thread
|
|
701
799
|
|
|
702
800
|
When a closed thread is rich (≥5 notes, ≥2 insight/move),
|
|
@@ -847,9 +945,20 @@ children start, a deterministic validator writes
|
|
|
847
945
|
ThreadKeeper/Claude Code/Codex/Agent Skills compatibility, resource/link
|
|
848
946
|
findings, mirror hashes, exact-body duplicate groups, and lexical candidates
|
|
849
947
|
for semantic review. System and installed-plugin sources are resolved from
|
|
850
|
-
their read-only caches rather than misreported as missing mirrors
|
|
851
|
-
|
|
852
|
-
|
|
948
|
+
their read-only caches rather than misreported as missing mirrors. A telemetry
|
|
949
|
+
row with no readable primary source becomes `unavailable`, is non-compatible,
|
|
950
|
+
and shows only `restore_source` until validation sees a source again; repeated
|
|
951
|
+
validation does not create duplicate repair work. A scoped Curator verifier can
|
|
952
|
+
archive or remove a confirmed registry-only orphan only after rechecking every
|
|
953
|
+
configured root, the primary archive, and external cache and saving its usage row plus
|
|
954
|
+
audit evidence to recovery trash. The same inventory also
|
|
955
|
+
checks Markdown links and unambiguous slash-containing inline-code resource
|
|
956
|
+
paths for missing local files. It ignores URLs, absolute or escaping paths,
|
|
957
|
+
shell fragments, frontmatter, headings, and fenced examples. It also reports
|
|
958
|
+
only substantial repeated prose: normalized paragraphs of at least 160
|
|
959
|
+
characters that occur at least three times in the same skill. The same findings
|
|
960
|
+
are returned by `skill_validate`, before a Curator repair is mirrored. The
|
|
961
|
+
inventory also flags a dense lesson subtopic when at least
|
|
853
962
|
`THREADKEEPER_CURATOR_PROMOTION_MIN_LESSONS` lessons (default 3) share two
|
|
854
963
|
concrete title terms and a non-generic body mechanism. Generic joins and
|
|
855
964
|
domain-wide/high-document-frequency title words cannot form a candidate. The
|
|
@@ -928,10 +1037,15 @@ have increased its patch counter. Patches are maintenance activity, not proof
|
|
|
928
1037
|
that a foreground user or agent consulted the skill.
|
|
929
1038
|
|
|
930
1039
|
Before spawning, the scheduler hashes lessons, concepts, skill bodies, support
|
|
931
|
-
trees, validators, and mirror state. It
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
1040
|
+
trees, validators, and mirror state. It persists the full pass audit manifest
|
|
1041
|
+
for parent coordination and provenance, then writes one smaller, hash-checked
|
|
1042
|
+
audit slice for every frozen batch. A worker reads only its slice: assigned
|
|
1043
|
+
skill records and their relevant consumer, link, mirror, source, duplicate, and
|
|
1044
|
+
candidate findings. A lesson-only batch receives an explicit no-skills slice
|
|
1045
|
+
instead of the full skill inventory. The scheduler stores the expected reports,
|
|
1046
|
+
slice hashes, and rendered text before launching any child. A dispatch is not
|
|
1047
|
+
completion: every batch must exit successfully and have a final, matching
|
|
1048
|
+
provenance record before the inventory is endorsed.
|
|
935
1049
|
Repeated manual calls over identical bytes return `unchanged_inventory` only
|
|
936
1050
|
after that endorsement; scheduled passes still run because CLI behavior,
|
|
937
1051
|
official guidance, and external alternatives can change without local file
|
|
@@ -995,7 +1109,26 @@ verifier) additionally lets the
|
|
|
995
1109
|
evaluator make in-place repairs to them. Lessons are
|
|
996
1110
|
stamped with an explicit `origin=<THREADKEEPER_WRITE_ORIGIN>` marker when
|
|
997
1111
|
appended; missing, legacy, or unknown lesson provenance is protected by
|
|
998
|
-
default.
|
|
1112
|
+
default. Protection preserves authored content; it does not certify that every
|
|
1113
|
+
factual claim is current. `lesson_verifications(slug)` returns the current
|
|
1114
|
+
lesson revision and its factual checks. After reading an official source,
|
|
1115
|
+
Curator can call `curator_verify_lesson(slug, lesson_revision, claim, status,
|
|
1116
|
+
source_url, source_revision)` with an exact claim excerpt, `verified`,
|
|
1117
|
+
`contradicted`, or `unsubstantiated`, an official HTTPS URL, and its revision
|
|
1118
|
+
identifier or ETag. When no official revision is available, omit
|
|
1119
|
+
`source_revision` and pass the checked page text as `source_text`; the server
|
|
1120
|
+
hashes it without retaining the text. Use a consistent revision identifier or
|
|
1121
|
+
page text for each URL. The server records check time separately from lesson
|
|
1122
|
+
content. Repeated checks update the same claim record. `lesson_get` and
|
|
1123
|
+
`lesson_list(query=...)` show source-linked warnings for contradicted or
|
|
1124
|
+
unsubstantiated claims. A changed lesson or an observed source revision change
|
|
1125
|
+
makes old checks require a new audit; a verified recheck clears the warning.
|
|
1126
|
+
Sources are checked by the caller: these tools do not fetch pages, certify
|
|
1127
|
+
domains, or detect remote changes between audits. Unavailable research means
|
|
1128
|
+
defer the check, not declare the claim unsubstantiated. Content edits still
|
|
1129
|
+
follow the existing approval and verifier rules.
|
|
1130
|
+
|
|
1131
|
+
`lesson_remove` and `skill_manage(action='delete')` refuse protected
|
|
999
1132
|
foreground/unknown-origin entries unless `force=True` is called from a
|
|
1000
1133
|
foreground writer or the caller is the Curator verifier phase; curator/spawned
|
|
1001
1134
|
children cannot elevate themselves with `force`. Before a destructive child is spawned, thread-keeper writes
|
|
@@ -1073,10 +1206,12 @@ embedding is closest to the prompt reached 25% recall at 12% precision.
|
|
|
1073
1206
|
|
|
1074
1207
|
Lesson access is tracked the same way skill access is: `lesson_list` increments
|
|
1075
1208
|
`lesson_usage.view_count` for displayed rows and `lesson_get` increments
|
|
1076
|
-
`lesson_usage.use_count` for the returned lesson.
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1209
|
+
`lesson_usage.use_count` for the returned lesson. Foreground and ordinary task
|
|
1210
|
+
reads count as consultations. Curator evaluator and verifier reads are neutral
|
|
1211
|
+
only while the caller owns a live task with a server-issued Curator launch
|
|
1212
|
+
record. This also applies to retries and every batch of a pass. An origin label
|
|
1213
|
+
or a caller-supplied pass ID cannot suppress normal usage. Curator dry runs
|
|
1214
|
+
include a ranked `STALE LESSONS (dry-run decay ranking)` section computed as
|
|
1080
1215
|
`access_frequency × exp(-days_since_access / tau)`, filtered to unprotected
|
|
1081
1216
|
lessons with no recent access and low pull-count. That decay list is advisory
|
|
1082
1217
|
only; it never becomes an automatic `lesson_remove` path by itself, and pinned
|
|
@@ -1170,27 +1305,44 @@ with that name instead of minting overlapping roadmap PRs.
|
|
|
1170
1305
|
|
|
1171
1306
|
The Evolve applier is the downstream implementer. `evolve_apply_roadmap_issue()`
|
|
1172
1307
|
picks one open GitHub issue at a time (`roadmap` label first, then FIFO), but
|
|
1173
|
-
the automatic pass first sweeps
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1308
|
+
the automatic pass first sweeps eligible PRs from the account thread-keeper's
|
|
1309
|
+
`gh` acts as. A PR must be in this repository and have a recognized automation
|
|
1310
|
+
branch (`roadmap/issue-…`, `evolve/apply-…`, or `docs/roadmap-audit-…`) or a
|
|
1311
|
+
standalone ownership marker in its body. Applier PRs use
|
|
1312
|
+
`<!-- thread-keeper:evolve-applier-pr -->`; reviewer roadmap PRs use
|
|
1313
|
+
`<!-- thread-keeper:evolve-reviewer-roadmap-pr -->`. Manual and fork PRs, and
|
|
1314
|
+
PRs with missing or conflicting ownership signals, stay read-only. If the PR
|
|
1315
|
+
sweep itself cannot read GitHub state or the `gh` account, the pass fails
|
|
1316
|
+
closed instead of taking fresh work blind.
|
|
1317
|
+
|
|
1318
|
+
The sweep squash-merges the oldest eligible non-draft PR GitHub reports
|
|
1319
|
+
`CLEAN` (up to date, required checks green) through the protected merge API,
|
|
1320
|
+
pinned to the head SHA it saw green, and then asks the oldest eligible `BEHIND`
|
|
1321
|
+
PR to update its branch so CI reruns against the new base. Strict branch
|
|
1183
1322
|
protection lets only one PR merge per base commit, so PRs land one at a time,
|
|
1184
1323
|
oldest first. Between full passes the daemon repeats only this cheap landing
|
|
1185
|
-
sweep every 15 minutes, so a green PR lands minutes after its checks finish;
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1324
|
+
sweep every 15 minutes, so a green PR lands minutes after its checks finish; it
|
|
1325
|
+
skips while any reviewer/applier git writer runs.
|
|
1326
|
+
|
|
1327
|
+
The applier keeps one applier PR (`roadmap/…` or `evolve/…` head branch in
|
|
1328
|
+
this repository) in flight at a time. While any is open it starts no new
|
|
1329
|
+
issue, Curator report, or evolve suggestion, and works on the oldest one until
|
|
1330
|
+
it lands. A conflicted PR gets a conflict-repair child that checks out the
|
|
1331
|
+
existing PR branch, merges the current base branch, resolves conflicts, runs
|
|
1332
|
+
the full suite, and pushes back to the same branch. A PR whose finished checks
|
|
1333
|
+
include a red one is first updated onto the newest base, which clears failures
|
|
1334
|
+
already fixed there. If it stays red while up to date, a fix child reads the
|
|
1335
|
+
failing logs, fixes the cause on the same branch (or re-runs a job that failed
|
|
1336
|
+
outside the code), runs the full suite, and pushes. A green applier draft is
|
|
1337
|
+
marked ready. Children never merge: the landing sweep lands the PR once it is
|
|
1338
|
+
green. When that PR needs a child, or the last open applier PR has just
|
|
1339
|
+
landed, the 15-minute sweep runs the full pass right away. After three repair
|
|
1340
|
+
or fix children one PR waits for a human and the next open applier PR moves
|
|
1341
|
+
ahead. When every open applier PR waits for a human, the pass records
|
|
1342
|
+
`ERR applier_prs_need_human=…`, which the notifier reports as a failure. A
|
|
1343
|
+
hand-made PR with conflicts or red checks waits for its author and does not
|
|
1344
|
+
hold back new work. Set `THREADKEEPER_EVOLVE_AUTOLAND=0` to leave every merge
|
|
1345
|
+
to a human.
|
|
1194
1346
|
The roadmap issue child skips issues carrying denylisted human-gate labels,
|
|
1195
1347
|
skips issues with an active Evolve claim comment, posts its own claim comment
|
|
1196
1348
|
before spawning, and advances to the next issue when an issue-local dispatch
|
|
@@ -1342,9 +1494,9 @@ the prior cursor and retries on a bounded short cadence; repeated identical
|
|
|
1342
1494
|
blockers are recorded once until the blocker changes. `evolve_apply_status()`
|
|
1343
1495
|
shows the last attempt, last successful dispatch, and any pending retry time.
|
|
1344
1496
|
Manual tools such as `evolve_apply_conflicted_pr()` and
|
|
1345
|
-
`evolve_apply_roadmap_issue()` dispatch immediately. If no
|
|
1346
|
-
|
|
1347
|
-
legacy promoted `evolve_format(...)` suggestions.
|
|
1497
|
+
`evolve_apply_roadmap_issue()` dispatch immediately. If no applier PR is open
|
|
1498
|
+
and no roadmap issue is startable, the pass falls back to Curator reports and
|
|
1499
|
+
then legacy promoted `evolve_format(...)` suggestions.
|
|
1348
1500
|
|
|
1349
1501
|
#### Honest take
|
|
1350
1502
|
|
|
@@ -1428,9 +1580,7 @@ after an update shows a one-time permission prompt.
|
|
|
1428
1580
|
`agent_status` feeds the app two lists — `recent_results` (named skill/lesson
|
|
1429
1581
|
write events plus completed-task history) and `recent_failures` (the two failure
|
|
1430
1582
|
sources above) — each item tagged with a `notify` flag computed from the toggles
|
|
1431
|
-
below. The app
|
|
1432
|
-
every item in its menu but only **posts a banner** for flagged ones, so turning a
|
|
1433
|
-
category off silences the banner without hiding the history. Each materialization
|
|
1583
|
+
below. The app only posts a banner for flagged items. Each materialization
|
|
1434
1584
|
uses its own skill or lesson toggle; generic task reports are history-only.
|
|
1435
1585
|
Foreground writes appear too, without waiting for a background child to finish.
|
|
1436
1586
|
A pathless skill mark only silences its reminder and has no materialization
|
|
@@ -1440,6 +1590,26 @@ values and private home paths are redacted before they reach the MCP status
|
|
|
1440
1590
|
response, menu, or notification; raw logs remain available only through
|
|
1441
1591
|
`task_logs`.
|
|
1442
1592
|
|
|
1593
|
+
**Reading a hidden or truncated banner.** The menu-bar popover's **Notification
|
|
1594
|
+
history** keeps the last 200 notification attempts, with the full text supplied
|
|
1595
|
+
to macOS and **Copy details** in each item's context menu. The app also imports
|
|
1596
|
+
its own delivered notifications still retained by Notification Center, so an
|
|
1597
|
+
older banner can be recovered even if previews are hidden. This local history
|
|
1598
|
+
survives app restarts and category toggles; it does not replay notifications or
|
|
1599
|
+
change macOS privacy settings. For diagnostics, the installed app prints the
|
|
1600
|
+
same history as JSON:
|
|
1601
|
+
|
|
1602
|
+
```bash
|
|
1603
|
+
~/Applications/ThreadKeeperAgentStatus.app/Contents/MacOS/ThreadKeeperAgentStatus --notification-history
|
|
1604
|
+
```
|
|
1605
|
+
|
|
1606
|
+
The daemon also stores each sanitized title/body as a node-local `notification`
|
|
1607
|
+
event before dispatch, including its source event or task, regardless of the
|
|
1608
|
+
selected channels. `notify_pass` remains the aggregate cursor/counter record.
|
|
1609
|
+
These records describe notification attempts, not proof that macOS displayed a
|
|
1610
|
+
banner. Older dismissed notifications without a saved payload cannot be
|
|
1611
|
+
reconstructed from counters alone.
|
|
1612
|
+
|
|
1443
1613
|
**Settings in the app.** The menu-bar app's **Settings ▸ Notifications** tab
|
|
1444
1614
|
edits these same `THREADKEEPER_NOTIFY_*` keys visually — switches for the
|
|
1445
1615
|
on/off categories, a picker for the interval, channel, and cooldown — and writes
|
|
@@ -1537,6 +1707,7 @@ the host after changing it:
|
|
|
1537
1707
|
| `coordination` | `core` plus child spawning, task status, pickup, and delegated search |
|
|
1538
1708
|
| `memory-admin` | `core` plus durable memory, concepts, lessons, graph links, and explicit erasure |
|
|
1539
1709
|
| `learning-loops` | `core` plus extraction, validation, skills, Curator, probes, and dialectic workflows |
|
|
1710
|
+
| `model-router` | only the pass-authorized `model_route_write` tool |
|
|
1540
1711
|
| `full` | every registered tool; the compatibility default when no profile is configured |
|
|
1541
1712
|
|
|
1542
1713
|
New `thread-keeper-setup` registrations use `core`. Existing server entries
|
|
@@ -1547,7 +1718,9 @@ server rather than exposing an unintended surface.
|
|
|
1547
1718
|
|
|
1548
1719
|
Spawned children default to `core`; archival, Curator, candidate-review,
|
|
1549
1720
|
shadow-review, probe-runner, and dialectic-validator roles use
|
|
1550
|
-
`learning-loops`,
|
|
1721
|
+
`learning-loops`, model-router children use `model-router`, and Evolve roles
|
|
1722
|
+
request `full`. A router refuses to spawn if its parent cannot expose the
|
|
1723
|
+
route-write tool. The server receives the
|
|
1551
1724
|
parent’s resolved allowlist and intersects it with the child profile, so a
|
|
1552
1725
|
child cannot regain a tool its parent did not expose.
|
|
1553
1726
|
`THREADKEEPER_CHILD_TOOL_PROFILE` explicitly selects a different child profile,
|
|
@@ -1560,7 +1733,7 @@ use it as the fallback on hosts that lack native deferred tool discovery.
|
|
|
1560
1733
|
|
|
1561
1734
|
| Knob | Default | Purpose |
|
|
1562
1735
|
|---|---|---|
|
|
1563
|
-
| `THREADKEEPER_TOOL_PROFILE` | `full` | MCP registry profile: `core`, `coordination`, `memory-admin`, `learning-loops`, or `full`; read at server start |
|
|
1736
|
+
| `THREADKEEPER_TOOL_PROFILE` | `full` | MCP registry profile: `core`, `coordination`, `memory-admin`, `learning-loops`, `model-router`, or `full`; read at server start |
|
|
1564
1737
|
| `THREADKEEPER_TOOL_INCLUDE` | "" | exact comma-separated tool names to add to the selected profile; unknown names fail closed |
|
|
1565
1738
|
| `THREADKEEPER_TOOL_EXCLUDE` | "" | exact comma-separated tool names to remove from the selected profile; unknown or overlapping names fail closed |
|
|
1566
1739
|
| `THREADKEEPER_CHILD_TOOL_PROFILE` | role default | spawned-child profile override; always intersected with the parent’s resolved tool surface |
|
|
@@ -1668,7 +1841,7 @@ use it as the fallback on hosts that lack native deferred tool discovery.
|
|
|
1668
1841
|
| `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 |
|
|
1669
1842
|
| `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 |
|
|
1670
1843
|
| `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 |
|
|
1671
|
-
| `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 |
|
|
1844
|
+
| `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. Applier PRs also get a green draft marked ready, and red checks retried on the newest base before a fix child starts. Other accounts' PRs are never touched. `0`/`false` leaves every merge to a human |
|
|
1672
1845
|
| `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 |
|
|
1673
1846
|
| `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 |
|
|
1674
1847
|
| `THREADKEEPER_EVOLVE_REPO_URL` | upstream repo | HTTPS `github.com` source for the managed clone; restart-only, and other hosts/schemes are refused |
|
|
@@ -1684,7 +1857,7 @@ use it as the fallback on hosts that lack native deferred tool discovery.
|
|
|
1684
1857
|
| `THREADKEEPER_ROADMAP_ISSUE_BACKOFF_BASE_S` | 172800 (2d) | base failure-backoff window for a roadmap issue; doubles per attempt (`base * 2^(attempts-1)`, capped at 30d). Defers re-selection of a repeatedly-aborting issue beyond the fixed 24h claim TTL |
|
|
1685
1858
|
| `THREADKEEPER_DIALECTIC_MAX_NEW_CLAIMS` | 3 | max new dialectic claims the validator may create per pass |
|
|
1686
1859
|
| `THREADKEEPER_DIALECTIC_OBS_MAX_REQUEUES` | 3 | requeues (validator child exited without resolving) before an observation is terminally skipped as poison; 0 = uncapped |
|
|
1687
|
-
| `THREADKEEPER_DAEMON_HOST` | `1` (on) | One headless host (`python -m threadkeeper.host`) owns the background loops + the warm embedding model + the embed socket, and per-session servers go thin (no daemons, no ONNX). `0` reverts to the legacy mode where every foreground MCP server runs its own daemon threads. See [Embeddings](#embeddings) below |
|
|
1860
|
+
| `THREADKEEPER_DAEMON_HOST` | `1` (on) | One headless host (`python -m threadkeeper.host`) owns the background loops + the warm embedding model + the embed socket, and per-session servers go thin (no daemons, no ONNX). `0` reverts to the legacy mode where every foreground MCP server runs its own daemon threads. No host is spawned for a `THREADKEEPER_DB` under the system temp directory or `/tmp` (test and eval runs). See [Embeddings](#embeddings) below |
|
|
1688
1861
|
| `THREADKEEPER_ROLE` | `server` | process role: `server` (default; per-session MCP server) or `host`. Set to `host` only by `python -m threadkeeper.host` — do not set this by hand |
|
|
1689
1862
|
| `THREADKEEPER_HOST_SOCK` | (auto) | embed-only unix socket the thin servers dial and the host binds; empty resolves to `<db dir>/host.sock` |
|
|
1690
1863
|
| `THREADKEEPER_HOST_HEARTBEAT_TTL_S` | 120 | host liveness window (s): how stale the host's presence heartbeat may get before `memory_guard`/a thin server treats it as dead and spawns a replacement |
|
|
@@ -1759,16 +1932,50 @@ model and effort:
|
|
|
1759
1932
|
THREADKEEPER_SPAWN__LOOP__SHADOW_OBSERVER=auto
|
|
1760
1933
|
```
|
|
1761
1934
|
|
|
1762
|
-
The router
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1935
|
+
The router compares models and effort for each role using the results of its
|
|
1936
|
+
previous tasks: task effectiveness, cost, and efficiency. Its last-30-day
|
|
1937
|
+
digest includes task instructions and final answers from saved transcripts,
|
|
1938
|
+
with structured CLI results or log summaries as a fallback. Samples cover
|
|
1939
|
+
different model/effort combinations and include failed executions. Time,
|
|
1940
|
+
tokens, recorded USD costs and missing-cost coverage accompany the results;
|
|
1941
|
+
subscription token use is a quota proxy, not an invented dollar price.
|
|
1942
|
+
|
|
1943
|
+
Before each decision pass, the parent fetches official OpenAI API and Codex
|
|
1944
|
+
credit rates, Anthropic API rates and Claude alias rules, GitHub Copilot rates,
|
|
1945
|
+
and Antigravity quota/overage rules for available CLIs. Rate cards are cached
|
|
1946
|
+
for 24 hours in `model_pricing.json` beside the database, with source URLs and
|
|
1947
|
+
fetch times. Network or document-layout failures retain the last good card
|
|
1948
|
+
as **stale**; absent rates remain unknown. Published API USD rates, Codex
|
|
1949
|
+
credits, GitHub AI credits and subscription quotas keep their own billing
|
|
1950
|
+
scope. The router uses observed input/output tokens, duration and results to
|
|
1951
|
+
compare effort; effort has no fixed invented price multiplier. Estimates
|
|
1952
|
+
state missing cache/reasoning or alias details and never replace recorded spend.
|
|
1953
|
+
Completed router executions also supply dated CLI/model/effort access evidence,
|
|
1954
|
+
so an older startup rejection is not treated as unresolved after a later success.
|
|
1955
|
+
Access evidence does not establish quality on other roles' tasks.
|
|
1956
|
+
Recent failed router attempts also carry their parsed error text, including
|
|
1957
|
+
temporary quota limits, separately from evidence of task quality.
|
|
1958
|
+
|
|
1959
|
+
Every pass reassesses alternatives, even when the current model runs without
|
|
1960
|
+
errors. Exit code zero does not prove task success, and missing results leave
|
|
1961
|
+
quality unknown. Each decision explains the task-specific tradeoff and its
|
|
1962
|
+
uncertainty. Until it has decided, `auto` keeps its old meaning and follows the
|
|
1766
1963
|
active CLI. While a role is routed, its `SPAWN__MODEL__<ROLE>` and
|
|
1767
1964
|
`SPAWN__EFFORT__<ROLE>` pins are ignored and `spawn_status()` warns about them.
|
|
1768
1965
|
|
|
1769
1966
|
The router runs on `claude` / `opus` / `max` (override with the usual
|
|
1770
1967
|
`SPAWN__LOOP|MODEL|EFFORT__MODEL_ROUTER` keys). If that run fails, the same pass
|
|
1771
1968
|
reruns on the fallback below; a pass that fails twice retries after 6 hours.
|
|
1969
|
+
Due-pass checks run hourly; unfinished passes reconcile every 30 seconds so
|
|
1970
|
+
a finished or failed child does not wait an hour for its next state transition.
|
|
1971
|
+
It decides from the prepared evidence and prices, rather than starting new
|
|
1972
|
+
research. Claude router children expose only native `ToolSearch` plus the MCP
|
|
1973
|
+
route writer. Captured headless Claude launches stream intermediate events
|
|
1974
|
+
to the task log so an active analysis is distinguishable from a stalled run.
|
|
1975
|
+
If the CLI rejects a model shown in the shared model cache, check
|
|
1976
|
+
`codex --version` and update the CLI before changing model pins. The desktop
|
|
1977
|
+
app and the CLI on `PATH` can use different releases. Verify access with a
|
|
1978
|
+
short call through the CLI that thread-keeper actually launches.
|
|
1772
1979
|
`model_router_status()` shows current decisions and `model_router_run()` runs a
|
|
1773
1980
|
pass now. Set `THREADKEEPER_MODEL_ROUTER_INTERVAL_S=0` to disable the router.
|
|
1774
1981
|
|
|
@@ -1792,6 +1999,17 @@ Three tools keep the memory tidy. `consolidate()` and `forget()` default to
|
|
|
1792
1999
|
`THREADKEEPER_TASK_RETENTION_DAYS` defaults to `30` and
|
|
1793
2000
|
`THREADKEEPER_TASK_RETENTION_COUNT` defaults to `1000`; a row is kept if it
|
|
1794
2001
|
is protected by either bound. Set either knob to `0` to disable that bound.
|
|
2002
|
+
With both bounds disabled, finished task rows and their checkouts are kept.
|
|
2003
|
+
Expired tasks also release their owned Git worktrees and temporary branches
|
|
2004
|
+
when the checkout is clean and its commits remain reachable from another
|
|
2005
|
+
local branch or a remote-tracking branch. Other temporary task branches do
|
|
2006
|
+
not count as a safe copy. Dry run reports checkout counts, bytes, and reasons
|
|
2007
|
+
for keeping work. Cleanup preserves live tasks, changed or untracked files
|
|
2008
|
+
(including ignored files), unpublished work, locked checkouts, changed
|
|
2009
|
+
ownership, and branches checked out elsewhere. It never forces Git removal.
|
|
2010
|
+
Commits saved only in the task's branch or checkout history are also kept,
|
|
2011
|
+
including commits left behind by a reset or branch switch.
|
|
2012
|
+
Ownership records survive task-history pruning, so a later cleanup can retry.
|
|
1795
2013
|
- **`forget(selector, selector_type="auto", dry_run=True)`** — targeted
|
|
1796
2014
|
privacy erasure for one session/cid/thread/dialog UUID. Dry-run reports the
|
|
1797
2015
|
rows that would be removed from `dialog_messages`, FTS/vector sidecars,
|
|
@@ -1835,6 +2053,22 @@ private child environment (and its slim MCP config), never in a prompt or CLI
|
|
|
1835
2053
|
argument. A watchdog continuation uses the prior agent span as its parent, so
|
|
1836
2054
|
retries remain in the same trace.
|
|
1837
2055
|
|
|
2056
|
+
For MCP `2026-07-28`, a host can add W3C `traceparent`, `tracestate`, and
|
|
2057
|
+
`baggage` values to the request `_meta`. A valid `traceparent` becomes the
|
|
2058
|
+
parent of the MCP operation, so the host and child work appear in one trace.
|
|
2059
|
+
Older MCP clients keep the existing local behavior. A missing or malformed
|
|
2060
|
+
host traceparent starts a local trace and does not fail the tool call.
|
|
2061
|
+
|
|
2062
|
+
ThreadKeeper accepts only the exact lowercase W3C `00` traceparent form. It
|
|
2063
|
+
keeps valid tracestate only when it has at most 32 entries and 512 characters,
|
|
2064
|
+
with W3C key and value characters. Baggage is more restrictive: it is capped
|
|
2065
|
+
at 256 characters and only forwards `deployment.environment`,
|
|
2066
|
+
`service.namespace`, and `threadkeeper.workflow_class` values made of up to 64
|
|
2067
|
+
safe identifier characters. All other baggage is dropped. These three values
|
|
2068
|
+
stay in private task tracing fields and child environment variables; they never appear
|
|
2069
|
+
in prompts, command arguments, memory, tool results, or exported span
|
|
2070
|
+
attributes.
|
|
2071
|
+
|
|
1838
2072
|
The exporter has a fixed allowlist: operation/tool identifier, latency and
|
|
1839
2073
|
queue wait, provider/model identifiers, input/output/total tokens, USD cost,
|
|
1840
2074
|
retry count, and terminal outcome. Operation names are fixed; tool/provider
|
|
@@ -1961,6 +2195,56 @@ first and copy `db.sqlite`, `db.sqlite-wal`, and `db.sqlite-shm` together. To
|
|
|
1961
2195
|
wipe memory, also stop thread-keeper first, then remove the main DB and both
|
|
1962
2196
|
sidecars.
|
|
1963
2197
|
|
|
2198
|
+
For a selective, human-inspectable migration or audit, use
|
|
2199
|
+
`tk-semantic-bundle`. It writes a versioned `manifest.json` and canonical
|
|
2200
|
+
`records.jsonl`; every record has a SHA-256 content hash, source namespace and
|
|
2201
|
+
ID, provenance/authority metadata, temporal fields, and deletion or
|
|
2202
|
+
invalidation state. It is not a disaster-recovery snapshot and does not
|
|
2203
|
+
replace active-active sync:
|
|
2204
|
+
|
|
2205
|
+
| Need | Use |
|
|
2206
|
+
| --- | --- |
|
|
2207
|
+
| Recover an exact local store after loss | `tk-backup` |
|
|
2208
|
+
| Keep live, compatible instances converged | instance sync |
|
|
2209
|
+
| Move or inspect selected semantic memory | `tk-semantic-bundle` |
|
|
2210
|
+
|
|
2211
|
+
```bash
|
|
2212
|
+
# Default: semantic threads, notes, concepts, distillations, lessons, skills,
|
|
2213
|
+
# and graph links. Raw dialog, task logs, and personal memory stay out.
|
|
2214
|
+
tk-semantic-bundle export ./memory.bundle --namespace laptop-2026
|
|
2215
|
+
|
|
2216
|
+
# Opt in to each sensitive class independently when it is needed.
|
|
2217
|
+
tk-semantic-bundle export ./complete.bundle --namespace laptop-2026 \
|
|
2218
|
+
--include-personal-memory --include-dialog --include-task-logs
|
|
2219
|
+
|
|
2220
|
+
# Import is a dry run unless --apply is explicit.
|
|
2221
|
+
tk-semantic-bundle import ./memory.bundle
|
|
2222
|
+
tk-semantic-bundle import ./memory.bundle --apply
|
|
2223
|
+
```
|
|
2224
|
+
|
|
2225
|
+
An import first validates the manifest schema and every hash, then reports
|
|
2226
|
+
additions, conflicts, invalid records, and its namespace choice without
|
|
2227
|
+
writing. Applied imports retain source IDs in the local
|
|
2228
|
+
`semantic_bundle_import_records` namespace ledger; an identical re-import is
|
|
2229
|
+
idempotent, while changed source content reports a deterministic conflict.
|
|
2230
|
+
The format has a documented crosswalk to the evolving
|
|
2231
|
+
[W3C AI Agent Memory Interoperability work](https://www.w3.org/groups/cg/ai-agent-memory-interop/)
|
|
2232
|
+
and [IETF AIMEM bundle draft](https://www.ietf.org/archive/id/draft-vu-aimem-bundle-00.html),
|
|
2233
|
+
but does not claim conformance to either draft. The crosswalk is deliberately
|
|
2234
|
+
conceptual, not a wire-format mapping:
|
|
2235
|
+
|
|
2236
|
+
| ThreadKeeper bundle v1 | External direction | Deliberate difference |
|
|
2237
|
+
| --- | --- | --- |
|
|
2238
|
+
| versioned manifest + canonical JSONL | AIMEM envelope and versioning | Directory/JSONL rather than the draft's one JSON object |
|
|
2239
|
+
| `source.namespace` + source-ID ledger | AIMEM producer namespace and replay identity | Local namespace strings are not AIMEM URNs |
|
|
2240
|
+
| record and stream SHA-256 hashes | AIMEM checksum/content-hash concepts | No signature or authenticity claim |
|
|
2241
|
+
| typed records and graph links | AIMEM chunks and edges | ThreadKeeper types and relations remain local |
|
|
2242
|
+
| egress class, authority, valid time, tombstone | W3C work on memory metadata, sharing, and revocation | Local policy metadata; not an external profile |
|
|
2243
|
+
|
|
2244
|
+
The IETF document is an Internet-Draft and the W3C group is still developing
|
|
2245
|
+
its protocol, so compatibility must be reviewed again before publishing an
|
|
2246
|
+
external-profile claim.
|
|
2247
|
+
|
|
1964
2248
|
### Opt-in encrypted storage (experimental)
|
|
1965
2249
|
|
|
1966
2250
|
The default `sqlite` profile is unchanged. For sensitive memory at rest, the
|
|
@@ -2104,6 +2388,18 @@ and visible `.command` files with no-follow owner-only opens. Git-backed spawns
|
|
|
2104
2388
|
also create their isolated worktrees there. `consolidate()` garbage-collects
|
|
2105
2389
|
task spool files once their task row is no longer retained.
|
|
2106
2390
|
|
|
2391
|
+
Task worktrees use the same retention bounds. Before removing history,
|
|
2392
|
+
`consolidate()` saves cleanup eligibility in a separate ownership record.
|
|
2393
|
+
It uses `git worktree remove` and deletes only the recorded temporary branch,
|
|
2394
|
+
after checking that its tip is retained elsewhere. Failed or interrupted cleanup
|
|
2395
|
+
keeps that record; rerun the dry run after saving work on another branch,
|
|
2396
|
+
publishing commits, or resolving the reported block. Apply cleanup only after
|
|
2397
|
+
reviewing that report. A changed branch or checkout must be reviewed manually.
|
|
2398
|
+
Older checkouts without ownership records are reported as `ownership_unknown`
|
|
2399
|
+
and kept; their task rows also stay available for manual review. Verify their
|
|
2400
|
+
Git status and saved commits before removing them
|
|
2401
|
+
manually with Git; directory names alone never establish ownership.
|
|
2402
|
+
|
|
2107
2403
|
---
|
|
2108
2404
|
|
|
2109
2405
|
## Embeddings
|
|
@@ -2464,9 +2760,17 @@ write is `dialectic_supersede`.
|
|
|
2464
2760
|
era. Legacy hosts retain the existing tools, resources, and prompts. Modern
|
|
2465
2761
|
calls derive identity and capabilities from every request, static discovery
|
|
2466
2762
|
catalogs advertise public cache freshness, and replaying a completed write with
|
|
2467
|
-
the same caller-bound JSON-RPC id
|
|
2468
|
-
committing a second mutation.
|
|
2469
|
-
|
|
2763
|
+
the same caller-bound JSON-RPC id within one stdio connection returns the
|
|
2764
|
+
original result instead of committing a second mutation. Independent CLI
|
|
2765
|
+
connections have separate replay namespaces even when their client metadata
|
|
2766
|
+
and numeric IDs match; numeric and string IDs are distinct. Sealed continuation
|
|
2767
|
+
state expires after five minutes; an interrupted write with no terminal result
|
|
2768
|
+
is rejected on replay within that connection. Durable workflow retries use
|
|
2769
|
+
their application handles, such as a router pass ID.
|
|
2770
|
+
The release gate also runs the pinned official MCP conformance requirement sets
|
|
2771
|
+
for both versions against a loopback-only Streamable HTTP view of this same
|
|
2772
|
+
registry. Its version-specific expected-failure baselines are checked for both
|
|
2773
|
+
new failures and stale entries; stdio keeps the ThreadKeeper-specific coverage.
|
|
2470
2774
|
|
|
2471
2775
|
Detailed map in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
|
|
2472
2776
|
Open work in [docs/ROADMAP.md](docs/ROADMAP.md) and the
|