shellbrain 0.1.20__tar.gz → 0.1.22__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.
- {shellbrain-0.1.20 → shellbrain-0.1.22}/PKG-INFO +1 -1
- shellbrain-0.1.22/app/boot/_dsn_resolution.py +45 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/boot/admin_db.py +16 -32
- shellbrain-0.1.22/app/boot/db.py +45 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/boot/read_policy.py +3 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/contracts/requests.py +10 -8
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/entities/associations.py +1 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/entities/memory.py +20 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/read_policy/pipeline.py +2 -9
- shellbrain-0.1.22/app/migrations/versions/20260410_0009_frontier_memory_family.py +96 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/claude/skills/shellbrain-session-start/SKILL.md +4 -4
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/codex/shellbrain-session-start/SKILL.md +4 -4
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/codex/shellbrain-session-start/references/session-workflow.md +4 -4
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/cursor/skills/shellbrain-session-start/SKILL.md +4 -4
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/repo_state.py +0 -29
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/cli/schema_validation.py +5 -6
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/repos/relational/read_policy_repo.py +18 -1
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/identity/claude_runtime.py +0 -11
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/identity/compatibility.py +0 -5
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/validation/integrity_validation.py +56 -1
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/validation/semantic_validation.py +1 -1
- {shellbrain-0.1.20 → shellbrain-0.1.22}/pyproject.toml +1 -1
- {shellbrain-0.1.20 → shellbrain-0.1.22}/shellbrain.egg-info/PKG-INFO +1 -1
- {shellbrain-0.1.20 → shellbrain-0.1.22}/shellbrain.egg-info/SOURCES.txt +2 -2
- shellbrain-0.1.20/app/boot/db.py +0 -70
- shellbrain-0.1.20/app/core/policies/read_policy/scenario_lift.py +0 -11
- shellbrain-0.1.20/app/core/policies/read_policy/utility_prior.py +0 -11
- {shellbrain-0.1.20 → shellbrain-0.1.22}/README.md +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/__main__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/boot/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/boot/config.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/boot/create_policy.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/boot/embeddings.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/boot/home.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/boot/migrations.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/boot/repos.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/boot/retrieval.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/boot/thresholds.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/boot/update_policy.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/boot/use_cases.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/config/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/config/defaults/create_policy.yaml +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/config/defaults/read_policy.yaml +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/config/defaults/runtime.yaml +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/config/defaults/thresholds.yaml +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/config/defaults/update_policy.yaml +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/config/loader.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/contracts/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/contracts/errors.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/contracts/responses.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/entities/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/entities/episodes.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/entities/evidence.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/entities/facts.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/entities/guidance.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/entities/identity.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/entities/runtime_context.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/entities/session_state.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/entities/telemetry.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/entities/utility.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/interfaces/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/interfaces/clock.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/interfaces/config.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/interfaces/embeddings.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/interfaces/idgen.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/interfaces/repos.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/interfaces/retrieval.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/interfaces/session_state_store.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/interfaces/unit_of_work.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/_shared/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/_shared/executor.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/_shared/side_effects.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/create_policy/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/create_policy/pipeline.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/read_policy/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/read_policy/bm25.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/read_policy/context_pack_builder.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/read_policy/expansion.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/read_policy/fusion_rrf.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/read_policy/lexical_query.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/read_policy/scoring.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/read_policy/seed_retrieval.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/update_policy/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/policies/update_policy/pipeline.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/use_cases/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/use_cases/build_guidance.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/use_cases/create_memory.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/use_cases/manage_session_state.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/use_cases/read_memory.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/use_cases/record_episode_sync_telemetry.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/use_cases/record_operation_telemetry.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/use_cases/sync_episode.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/core/use_cases/update_memory.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/migrations/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/migrations/env.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/migrations/versions/20260226_0001_initial_schema.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/migrations/versions/20260312_0002_add_hard_invariants.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/migrations/versions/20260312_0003_drop_create_confidence.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/migrations/versions/20260313_0004_episode_sync_hardening.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/migrations/versions/20260313_0005_evidence_episode_event_refs.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/migrations/versions/20260318_0006_usage_telemetry_schema.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/migrations/versions/20260319_0007_identity_session_guidance.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/migrations/versions/20260320_0008_instance_metadata_and_backup_safety.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/migrations/versions/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/claude/CLAUDE.md +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/claude/skills/shellbrain-usage-review/SKILL.md +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/codex/AGENTS.md +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/codex/shellbrain-session-start/agents/openai.yaml +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/codex/shellbrain-session-start/assets/shellbrain-large.svg +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/codex/shellbrain-session-start/assets/shellbrain-small.svg +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/codex/shellbrain-session-start/assets/shellbrain_logo.png +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/codex/shellbrain-session-start/references/request-shapes.md +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/codex/shellbrain-usage-review/SKILL.md +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/codex/shellbrain-usage-review/agents/openai.yaml +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/codex/shellbrain-usage-review/assets/shellbrain-small.svg +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/codex/shellbrain-usage-review/assets/shellbrain_logo.png +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/onboarding_assets/cursor/skills/shellbrain-usage-review/SKILL.md +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/agent_behavior_analysis.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/analytics.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/analytics_diagnostics.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/analytics_queries.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/backup.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/destructive_guard.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/doctor.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/external_runtime.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/init.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/init_errors.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/instance_guard.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/machine_state.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/managed_runtime.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/privileges.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/restore.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/storage_setup.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/admin/upgrade.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/cli/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/cli/handlers.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/cli/hydration.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/cli/main.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/cli/presenter_json.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/engine.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/models/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/models/associations.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/models/episodes.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/models/evidence.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/models/experiences.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/models/instance_metadata.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/models/memories.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/models/metadata.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/models/registry.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/models/telemetry.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/models/utility.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/models/views.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/repos/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/repos/relational/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/repos/relational/associations_repo.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/repos/relational/episodes_repo.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/repos/relational/evidence_repo.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/repos/relational/experiences_repo.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/repos/relational/memories_repo.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/repos/relational/telemetry_repo.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/repos/relational/utility_repo.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/repos/semantic/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/repos/semantic/keyword_retrieval_repo.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/repos/semantic/semantic_retrieval_repo.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/session.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/uow.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/embeddings/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/embeddings/local_provider.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/embeddings/query_vector_search.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/episodes/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/episodes/claude_code.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/episodes/codex.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/episodes/cursor.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/episodes/launcher.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/episodes/normalization.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/episodes/poller.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/episodes/poller_lock.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/episodes/source_discovery.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/episodes/tool_filter.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/identity/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/identity/claude_hook_install.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/identity/codex_runtime.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/identity/resolver.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/metrics/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/metrics/artifacts.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/metrics/browser.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/metrics/queries.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/metrics/render_html.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/metrics/service.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/onboarding/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/onboarding/host_assets.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/session_state/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/session_state/file_store.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/telemetry/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/telemetry/operation_summary.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/telemetry/session_selection.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/telemetry/sync_summary.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/validation/__init__.py +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/setup.cfg +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/shellbrain.egg-info/dependency_links.txt +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/shellbrain.egg-info/entry_points.txt +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/shellbrain.egg-info/requires.txt +0 -0
- {shellbrain-0.1.20 → shellbrain-0.1.22}/shellbrain.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Shared helpers for resolving configured application and admin DSNs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from typing import Any, Callable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def resolve_database_dsn(
|
|
10
|
+
*,
|
|
11
|
+
load_machine_config: Callable[[], tuple[object | None, str | None]],
|
|
12
|
+
runtime_provider: Callable[[], dict[str, Any]],
|
|
13
|
+
machine_field: str,
|
|
14
|
+
runtime_env_key: str,
|
|
15
|
+
required: bool,
|
|
16
|
+
) -> str | None:
|
|
17
|
+
"""Resolve one configured DSN from machine config first, then runtime env config."""
|
|
18
|
+
|
|
19
|
+
machine_config, machine_error = load_machine_config()
|
|
20
|
+
if machine_error:
|
|
21
|
+
if required:
|
|
22
|
+
raise RuntimeError(
|
|
23
|
+
"Shellbrain machine config is unreadable. Rerun `shellbrain init` to repair it."
|
|
24
|
+
)
|
|
25
|
+
return None
|
|
26
|
+
if machine_config is not None:
|
|
27
|
+
return getattr(machine_config.database, machine_field)
|
|
28
|
+
|
|
29
|
+
runtime = runtime_provider()
|
|
30
|
+
database = runtime.get("database")
|
|
31
|
+
if not isinstance(database, dict):
|
|
32
|
+
if required:
|
|
33
|
+
raise RuntimeError("runtime.database must be configured")
|
|
34
|
+
return None
|
|
35
|
+
|
|
36
|
+
env_name = database.get(runtime_env_key)
|
|
37
|
+
if not isinstance(env_name, str) or not env_name:
|
|
38
|
+
if required:
|
|
39
|
+
raise RuntimeError(f"runtime.database.{runtime_env_key} must be configured")
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
dsn = os.getenv(env_name)
|
|
43
|
+
if not dsn and required:
|
|
44
|
+
raise RuntimeError(f"{env_name} is not set")
|
|
45
|
+
return dsn or None
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import os
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
+
from app.boot._dsn_resolution import resolve_database_dsn
|
|
8
9
|
from app.boot.config import get_config_provider
|
|
9
10
|
from app.boot.home import get_machine_backups_dir
|
|
10
11
|
from app.periphery.admin.machine_state import try_load_machine_config
|
|
@@ -13,44 +14,15 @@ from app.periphery.admin.machine_state import try_load_machine_config
|
|
|
13
14
|
def get_admin_db_dsn() -> str:
|
|
14
15
|
"""Resolve the privileged admin DSN from environment-backed runtime config."""
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
raise RuntimeError(
|
|
19
|
-
"Shellbrain machine config is unreadable. Rerun `shellbrain init` to repair it."
|
|
20
|
-
)
|
|
21
|
-
if machine_config is not None:
|
|
22
|
-
return machine_config.database.admin_dsn
|
|
23
|
-
|
|
24
|
-
runtime = get_config_provider().get_runtime()
|
|
25
|
-
database = runtime.get("database")
|
|
26
|
-
if not isinstance(database, dict):
|
|
27
|
-
raise RuntimeError("runtime.database must be configured")
|
|
28
|
-
admin_dsn_env = database.get("admin_dsn_env")
|
|
29
|
-
if not isinstance(admin_dsn_env, str) or not admin_dsn_env:
|
|
30
|
-
raise RuntimeError("runtime.database.admin_dsn_env must be configured")
|
|
31
|
-
dsn = os.getenv(admin_dsn_env)
|
|
32
|
-
if not dsn:
|
|
33
|
-
raise RuntimeError(f"{admin_dsn_env} is not set")
|
|
17
|
+
dsn = _resolve_admin_db_dsn(required=True)
|
|
18
|
+
assert dsn is not None
|
|
34
19
|
return dsn
|
|
35
20
|
|
|
36
21
|
|
|
37
22
|
def get_optional_admin_db_dsn() -> str | None:
|
|
38
23
|
"""Resolve the privileged admin DSN when present, otherwise return None."""
|
|
39
24
|
|
|
40
|
-
|
|
41
|
-
if machine_error:
|
|
42
|
-
return None
|
|
43
|
-
if machine_config is not None:
|
|
44
|
-
return machine_config.database.admin_dsn
|
|
45
|
-
|
|
46
|
-
runtime = get_config_provider().get_runtime()
|
|
47
|
-
database = runtime.get("database")
|
|
48
|
-
if not isinstance(database, dict):
|
|
49
|
-
return None
|
|
50
|
-
admin_dsn_env = database.get("admin_dsn_env")
|
|
51
|
-
if not isinstance(admin_dsn_env, str) or not admin_dsn_env:
|
|
52
|
-
return None
|
|
53
|
-
return os.getenv(admin_dsn_env)
|
|
25
|
+
return _resolve_admin_db_dsn(required=False)
|
|
54
26
|
|
|
55
27
|
|
|
56
28
|
def get_backup_dir() -> Path:
|
|
@@ -86,3 +58,15 @@ def get_instance_mode_default() -> str:
|
|
|
86
58
|
"""Resolve the default instance mode used when stamping metadata for the current DB."""
|
|
87
59
|
|
|
88
60
|
return os.getenv("SHELLBRAIN_INSTANCE_MODE", "live").strip().lower() or "live"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _resolve_admin_db_dsn(*, required: bool) -> str | None:
|
|
64
|
+
"""Resolve the admin DSN from machine config or runtime env config."""
|
|
65
|
+
|
|
66
|
+
return resolve_database_dsn(
|
|
67
|
+
load_machine_config=try_load_machine_config,
|
|
68
|
+
runtime_provider=lambda: get_config_provider().get_runtime(),
|
|
69
|
+
machine_field="admin_dsn",
|
|
70
|
+
runtime_env_key="admin_dsn_env",
|
|
71
|
+
required=required,
|
|
72
|
+
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""This module defines boot-time factory helpers for database engine and sessions."""
|
|
2
|
+
|
|
3
|
+
from app.boot._dsn_resolution import resolve_database_dsn
|
|
4
|
+
from app.boot.config import get_config_provider
|
|
5
|
+
from app.periphery.admin.machine_state import try_load_machine_config
|
|
6
|
+
from app.periphery.db.engine import get_engine
|
|
7
|
+
from app.periphery.db.session import get_session_factory
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_db_dsn() -> str:
|
|
11
|
+
"""This function resolves the database DSN from environment configuration."""
|
|
12
|
+
|
|
13
|
+
dsn = _resolve_app_db_dsn(required=True)
|
|
14
|
+
assert dsn is not None
|
|
15
|
+
return dsn
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_optional_db_dsn() -> str | None:
|
|
19
|
+
"""Resolve the application DSN when present, otherwise return None."""
|
|
20
|
+
|
|
21
|
+
return _resolve_app_db_dsn(required=False)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_engine_instance():
|
|
25
|
+
"""This function builds a shared SQLAlchemy engine for the application."""
|
|
26
|
+
|
|
27
|
+
return get_engine(get_db_dsn())
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_session_factory_instance():
|
|
31
|
+
"""This function builds a reusable SQLAlchemy session factory for the app."""
|
|
32
|
+
|
|
33
|
+
return get_session_factory(get_engine_instance())
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _resolve_app_db_dsn(*, required: bool) -> str | None:
|
|
37
|
+
"""Resolve the application DSN from machine config or runtime env config."""
|
|
38
|
+
|
|
39
|
+
return resolve_database_dsn(
|
|
40
|
+
load_machine_config=try_load_machine_config,
|
|
41
|
+
runtime_provider=lambda: get_config_provider().get_runtime(),
|
|
42
|
+
machine_field="app_dsn",
|
|
43
|
+
runtime_env_key="dsn_env",
|
|
44
|
+
required=required,
|
|
45
|
+
)
|
|
@@ -4,6 +4,7 @@ from copy import deepcopy
|
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
6
|
from app.boot.config import get_config_provider
|
|
7
|
+
from app.core.entities.memory import MATURE_MEMORY_KIND_VALUES
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
_SUPPORTED_MODES = ("targeted", "ambient")
|
|
@@ -164,6 +165,8 @@ def resolve_read_payload_defaults(payload: dict[str, Any]) -> dict[str, Any]:
|
|
|
164
165
|
resolved["include_global"] = settings["include_global"]
|
|
165
166
|
if resolved.get("limit") is None:
|
|
166
167
|
resolved["limit"] = settings["limits_by_mode"][resolved["mode"]]
|
|
168
|
+
if resolved.get("kinds") is None:
|
|
169
|
+
resolved["kinds"] = list(MATURE_MEMORY_KIND_VALUES)
|
|
167
170
|
|
|
168
171
|
incoming_expand = resolved.get("expand")
|
|
169
172
|
merged_expand = deepcopy(settings["expand"])
|
|
@@ -5,6 +5,10 @@ from typing import Annotated, Literal
|
|
|
5
5
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
MemoryKindValue = Literal["problem", "solution", "failed_tactic", "fact", "preference", "change", "frontier"]
|
|
9
|
+
AssociationRelationValue = Literal["depends_on", "associated_with", "matures_into"]
|
|
10
|
+
|
|
11
|
+
|
|
8
12
|
class StrictBaseModel(BaseModel):
|
|
9
13
|
"""This base model enforces strict schemas by rejecting unknown fields."""
|
|
10
14
|
|
|
@@ -30,9 +34,7 @@ class MemoryReadRequest(StrictBaseModel):
|
|
|
30
34
|
mode: Literal["ambient", "targeted"]
|
|
31
35
|
query: str = Field(min_length=1)
|
|
32
36
|
include_global: bool | None = None
|
|
33
|
-
kinds: (
|
|
34
|
-
list[Literal["problem", "solution", "failed_tactic", "fact", "preference", "change"]] | None
|
|
35
|
-
) = None
|
|
37
|
+
kinds: list[MemoryKindValue] | None = Field(default=None, min_length=1)
|
|
36
38
|
limit: int | None = Field(default=None, ge=1, le=100)
|
|
37
39
|
expand: ReadExpandRequest | None = None
|
|
38
40
|
|
|
@@ -40,8 +42,8 @@ class MemoryReadRequest(StrictBaseModel):
|
|
|
40
42
|
@classmethod
|
|
41
43
|
def _validate_kinds_unique(
|
|
42
44
|
cls,
|
|
43
|
-
value: list[
|
|
44
|
-
) -> list[
|
|
45
|
+
value: list[MemoryKindValue] | None,
|
|
46
|
+
) -> list[MemoryKindValue] | None:
|
|
45
47
|
"""This validator enforces unique kinds filters for read requests."""
|
|
46
48
|
|
|
47
49
|
if value is None:
|
|
@@ -63,7 +65,7 @@ class MemoryCreateAssociationLink(StrictBaseModel):
|
|
|
63
65
|
"""This model defines a typed explicit association link payload on create."""
|
|
64
66
|
|
|
65
67
|
to_memory_id: str
|
|
66
|
-
relation_type:
|
|
68
|
+
relation_type: AssociationRelationValue
|
|
67
69
|
confidence: float | None = Field(default=None, ge=0.0, le=1.0)
|
|
68
70
|
salience: float | None = Field(default=None, ge=0.0, le=1.0)
|
|
69
71
|
rationale: str | None = None
|
|
@@ -91,7 +93,7 @@ class MemoryCreateBody(StrictBaseModel):
|
|
|
91
93
|
|
|
92
94
|
text: str
|
|
93
95
|
scope: Literal["repo", "global"]
|
|
94
|
-
kind:
|
|
96
|
+
kind: MemoryKindValue
|
|
95
97
|
rationale: str | None = None
|
|
96
98
|
links: MemoryCreateLinks = Field(default_factory=MemoryCreateLinks)
|
|
97
99
|
evidence_refs: list[str] = Field(min_length=1)
|
|
@@ -165,7 +167,7 @@ class AssociationLinkUpdate(StrictBaseModel):
|
|
|
165
167
|
|
|
166
168
|
type: Literal["association_link"]
|
|
167
169
|
to_memory_id: str
|
|
168
|
-
relation_type:
|
|
170
|
+
relation_type: AssociationRelationValue
|
|
169
171
|
confidence: float | None = Field(default=None, ge=0.0, le=1.0)
|
|
170
172
|
salience: float | None = Field(default=None, ge=0.0, le=1.0)
|
|
171
173
|
rationale: str | None = None
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from enum import Enum
|
|
5
|
+
from typing import Final
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
class MemoryKind(str, Enum):
|
|
@@ -13,6 +14,25 @@ class MemoryKind(str, Enum):
|
|
|
13
14
|
FACT = "fact"
|
|
14
15
|
PREFERENCE = "preference"
|
|
15
16
|
CHANGE = "change"
|
|
17
|
+
FRONTIER = "frontier"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
MATURE_MEMORY_KINDS: Final[tuple[MemoryKind, ...]] = (
|
|
21
|
+
MemoryKind.PROBLEM,
|
|
22
|
+
MemoryKind.SOLUTION,
|
|
23
|
+
MemoryKind.FAILED_TACTIC,
|
|
24
|
+
MemoryKind.FACT,
|
|
25
|
+
MemoryKind.PREFERENCE,
|
|
26
|
+
MemoryKind.CHANGE,
|
|
27
|
+
)
|
|
28
|
+
MATURE_MEMORY_KIND_VALUES: Final[tuple[str, ...]] = tuple(kind.value for kind in MATURE_MEMORY_KINDS)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def is_mature_memory_kind(kind: MemoryKind | str) -> bool:
|
|
32
|
+
"""Return whether one kind belongs to the mature durable-memory set."""
|
|
33
|
+
|
|
34
|
+
normalized_kind = kind if isinstance(kind, MemoryKind) else MemoryKind(kind)
|
|
35
|
+
return normalized_kind in MATURE_MEMORY_KINDS
|
|
16
36
|
|
|
17
37
|
|
|
18
38
|
class MemoryScope(str, Enum):
|
|
@@ -8,10 +8,8 @@ from app.core.interfaces.retrieval import IVectorSearch
|
|
|
8
8
|
from app.core.policies.read_policy.context_pack_builder import assemble_context_pack
|
|
9
9
|
from app.core.policies.read_policy.expansion import expand_candidates
|
|
10
10
|
from app.core.policies.read_policy.fusion_rrf import fuse_with_rrf
|
|
11
|
-
from app.core.policies.read_policy.scenario_lift import derive_scenarios
|
|
12
11
|
from app.core.policies.read_policy.scoring import score_candidates
|
|
13
12
|
from app.core.policies.read_policy.seed_retrieval import retrieve_seeds
|
|
14
|
-
from app.core.policies.read_policy.utility_prior import apply_utility_prior
|
|
15
13
|
|
|
16
14
|
|
|
17
15
|
def build_context_pack(
|
|
@@ -45,13 +43,8 @@ def build_context_pack(
|
|
|
45
43
|
"implicit": expanded_candidates["implicit"],
|
|
46
44
|
}
|
|
47
45
|
scored_candidates = score_candidates(bucketed_candidates, payload)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
for bucket_name, candidates in scored_candidates.items()
|
|
51
|
-
}
|
|
52
|
-
pack = assemble_context_pack(adjusted_candidates, payload)
|
|
53
|
-
hydrated_pack = _hydrate_pack_items(pack, memories)
|
|
54
|
-
return derive_scenarios(hydrated_pack, payload)["pack"]
|
|
46
|
+
pack = assemble_context_pack(scored_candidates, payload)
|
|
47
|
+
return _hydrate_pack_items(pack, memories)
|
|
55
48
|
|
|
56
49
|
|
|
57
50
|
def _resolve_read_defaults(payload: dict[str, Any]) -> dict[str, Any]:
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""Add frontier memory kind and matures_into association relation constraints."""
|
|
2
|
+
|
|
3
|
+
from alembic import op
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
revision = "20260410_0009"
|
|
7
|
+
down_revision = "20260320_0008"
|
|
8
|
+
branch_labels = None
|
|
9
|
+
depends_on = None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _drop_check_constraint(table_name: str, required_snippets: list[str]) -> None:
|
|
13
|
+
"""Drop one unnamed CHECK constraint by matching its rendered definition."""
|
|
14
|
+
|
|
15
|
+
like_clauses = " AND ".join(
|
|
16
|
+
f"pg_get_constraintdef(con.oid) LIKE '%{snippet}%'" for snippet in required_snippets
|
|
17
|
+
)
|
|
18
|
+
op.execute(
|
|
19
|
+
f"""
|
|
20
|
+
DO $$
|
|
21
|
+
DECLARE constraint_name TEXT;
|
|
22
|
+
BEGIN
|
|
23
|
+
SELECT con.conname
|
|
24
|
+
INTO constraint_name
|
|
25
|
+
FROM pg_constraint con
|
|
26
|
+
JOIN pg_class rel ON rel.oid = con.conrelid
|
|
27
|
+
JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace
|
|
28
|
+
WHERE nsp.nspname = current_schema()
|
|
29
|
+
AND rel.relname = '{table_name}'
|
|
30
|
+
AND con.contype = 'c'
|
|
31
|
+
AND {like_clauses}
|
|
32
|
+
LIMIT 1;
|
|
33
|
+
|
|
34
|
+
IF constraint_name IS NOT NULL THEN
|
|
35
|
+
EXECUTE format('ALTER TABLE {table_name} DROP CONSTRAINT %I', constraint_name);
|
|
36
|
+
END IF;
|
|
37
|
+
END $$;
|
|
38
|
+
"""
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def upgrade() -> None:
|
|
43
|
+
"""Widen durable-memory and association relation constraints for frontier support."""
|
|
44
|
+
|
|
45
|
+
_drop_check_constraint("memories", ["kind", "problem", "change"])
|
|
46
|
+
_drop_check_constraint("association_edges", ["relation_type", "depends_on", "associated_with"])
|
|
47
|
+
_drop_check_constraint("association_observations", ["relation_type", "depends_on", "associated_with"])
|
|
48
|
+
|
|
49
|
+
op.execute(
|
|
50
|
+
"""
|
|
51
|
+
ALTER TABLE memories
|
|
52
|
+
ADD CONSTRAINT ck_memories_kind_ratified
|
|
53
|
+
CHECK (kind IN ('problem', 'solution', 'failed_tactic', 'fact', 'preference', 'change', 'frontier'));
|
|
54
|
+
|
|
55
|
+
ALTER TABLE association_edges
|
|
56
|
+
ADD CONSTRAINT ck_association_edges_relation_type
|
|
57
|
+
CHECK (relation_type IN ('depends_on', 'associated_with', 'matures_into'));
|
|
58
|
+
|
|
59
|
+
ALTER TABLE association_observations
|
|
60
|
+
ADD CONSTRAINT ck_association_observations_relation_type
|
|
61
|
+
CHECK (relation_type IN ('depends_on', 'associated_with', 'matures_into'));
|
|
62
|
+
"""
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def downgrade() -> None:
|
|
67
|
+
"""Restore the prior durable-memory and association relation constraint set."""
|
|
68
|
+
|
|
69
|
+
op.execute(
|
|
70
|
+
"""
|
|
71
|
+
ALTER TABLE association_observations
|
|
72
|
+
DROP CONSTRAINT IF EXISTS ck_association_observations_relation_type;
|
|
73
|
+
|
|
74
|
+
ALTER TABLE association_edges
|
|
75
|
+
DROP CONSTRAINT IF EXISTS ck_association_edges_relation_type;
|
|
76
|
+
|
|
77
|
+
ALTER TABLE memories
|
|
78
|
+
DROP CONSTRAINT IF EXISTS ck_memories_kind_ratified;
|
|
79
|
+
"""
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
op.execute(
|
|
83
|
+
"""
|
|
84
|
+
ALTER TABLE memories
|
|
85
|
+
ADD CONSTRAINT ck_memories_kind_ratified
|
|
86
|
+
CHECK (kind IN ('problem', 'solution', 'failed_tactic', 'fact', 'preference', 'change'));
|
|
87
|
+
|
|
88
|
+
ALTER TABLE association_edges
|
|
89
|
+
ADD CONSTRAINT ck_association_edges_relation_type
|
|
90
|
+
CHECK (relation_type IN ('depends_on', 'associated_with'));
|
|
91
|
+
|
|
92
|
+
ALTER TABLE association_observations
|
|
93
|
+
ADD CONSTRAINT ck_association_observations_relation_type
|
|
94
|
+
CHECK (relation_type IN ('depends_on', 'associated_with'));
|
|
95
|
+
"""
|
|
96
|
+
)
|
|
@@ -26,10 +26,10 @@ Treat current repo state as ground truth. Treat Shellbrain as advisory long-term
|
|
|
26
26
|
2. Otherwise, do not rerun `init` just because a new agent session started. Start with focused `read` queries right away.
|
|
27
27
|
3. If readiness is unclear, inspect with `shellbrain admin doctor` instead of rerunning `init` by reflex.
|
|
28
28
|
4. If `doctor` reports `repair_needed`, rerun `shellbrain init` instead of trying to repair Shellbrain manually.
|
|
29
|
-
5. In Claude Code, if direct `shellbrain` calls fail in the current session,
|
|
30
|
-
- `zsh -lc 'source ~/.zprofile >/dev/null 2>&1; shellbrain
|
|
31
|
-
- `bash -lc 'source ~/.bash_profile >/dev/null 2>&1; shellbrain
|
|
32
|
-
6. If the
|
|
29
|
+
5. In Claude Code, if direct `shellbrain` calls fail in the current session, do a one-time login-shell retry that sources the user's login profile and resolves the CLI path:
|
|
30
|
+
- `zsh -lc 'source ~/.zprofile >/dev/null 2>&1; command -v shellbrain'`
|
|
31
|
+
- `bash -lc 'source ~/.bash_profile >/dev/null 2>&1; command -v shellbrain'`
|
|
32
|
+
6. Do not keep sourcing the login profile on every Shellbrain command. Once `shellbrain` is visible, use plain `shellbrain ...`. If the host tool keeps starting fresh shells without your login PATH, reuse the absolute path returned by `command -v shellbrain` instead of re-sourcing the profile on every call. If the one-time login-shell retry still cannot find `shellbrain`, inspect Python's user script directory:
|
|
33
33
|
- `python3 -c "import sysconfig; print(sysconfig.get_path('scripts', 'posix_user'))"`
|
|
34
34
|
If `shellbrain` exists there, call it directly or add that directory to the login profile PATH and retry. If it does not, reinstall the Shellbrain CLI.
|
|
35
35
|
7. Resolve the target repo:
|
|
@@ -31,10 +31,10 @@ Treat current repo state as ground truth. Treat Shellbrain as advisory long-term
|
|
|
31
31
|
2. Otherwise, do not rerun `init` just because a new agent session started. Start with focused `read` queries right away.
|
|
32
32
|
3. If readiness is unclear, inspect with `shellbrain admin doctor` instead of rerunning `init` by reflex.
|
|
33
33
|
4. If `doctor` reports `repair_needed`, rerun `shellbrain init` instead of trying to repair Shellbrain manually.
|
|
34
|
-
5. In Codex or similar tool shells, if direct `shellbrain` calls fail in the current session,
|
|
35
|
-
- `zsh -lc 'source ~/.zprofile >/dev/null 2>&1; shellbrain
|
|
36
|
-
- `bash -lc 'source ~/.bash_profile >/dev/null 2>&1; shellbrain
|
|
37
|
-
6. If the
|
|
34
|
+
5. In Codex or similar tool shells, if direct `shellbrain` calls fail in the current session, do a one-time login-shell retry that sources the user's login profile and resolves the CLI path:
|
|
35
|
+
- `zsh -lc 'source ~/.zprofile >/dev/null 2>&1; command -v shellbrain'`
|
|
36
|
+
- `bash -lc 'source ~/.bash_profile >/dev/null 2>&1; command -v shellbrain'`
|
|
37
|
+
6. Do not keep sourcing the login profile on every Shellbrain command. Once `shellbrain` is visible, use plain `shellbrain ...`. If the host tool keeps starting fresh shells without your login PATH, reuse the absolute path returned by `command -v shellbrain` instead of re-sourcing the profile on every call. If the one-time login-shell retry still cannot find `shellbrain`, inspect Python's user script directory:
|
|
38
38
|
- `python3 -c "import sysconfig; print(sysconfig.get_path('scripts', 'posix_user'))"`
|
|
39
39
|
If `shellbrain` exists there, call it directly or add that directory to the login profile PATH and retry. If it does not, reinstall the Shellbrain CLI.
|
|
40
40
|
7. Resolve the target repo:
|
|
@@ -43,13 +43,13 @@ Use Shellbrain normally after `doctor` shows the machine bootstrap is `ready` an
|
|
|
43
43
|
|
|
44
44
|
If `doctor` reports `repair_needed`, rerun `shellbrain init` instead of trying to patch Shellbrain manually.
|
|
45
45
|
|
|
46
|
-
In Codex desktop and similar tool shells, if direct `shellbrain` calls fail in the current session,
|
|
46
|
+
In Codex desktop and similar tool shells, if direct `shellbrain` calls fail in the current session, do a one-time login-shell retry that sources `~/.zprofile` and resolves the CLI path:
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
|
-
zsh -lc 'source ~/.zprofile >/dev/null 2>&1; shellbrain
|
|
49
|
+
zsh -lc 'source ~/.zprofile >/dev/null 2>&1; command -v shellbrain'
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
Assume Shellbrain comes from a one-time machine install. Do not rerun `init` just because a new agent starts.
|
|
52
|
+
Assume Shellbrain comes from a one-time machine install. Do not rerun `init` just because a new agent starts. Do not keep sourcing the login profile on every Shellbrain command. The login-shell step is only a one-time availability and PATH check when direct calls fail. Once `shellbrain` is visible, use plain `shellbrain ...`. If the host tool keeps starting fresh shells without your login PATH, resolve the absolute path once with `command -v shellbrain` and reuse that path for later invocations. Only if the one-time login-shell retry fails should you ask the operator to restore the machine-level install.
|
|
53
53
|
|
|
54
54
|
Drop into the advanced/operator path only when `doctor` says the managed runtime is blocked.
|
|
55
55
|
|
|
@@ -228,7 +228,7 @@ Important modeling pattern for changed truth:
|
|
|
228
228
|
Do not rerun `init`. Start with `read`. Use `doctor` only if readiness is unclear.
|
|
229
229
|
|
|
230
230
|
- `shellbrain: command not found`
|
|
231
|
-
Retry through `zsh -lc 'source ~/.zprofile >/dev/null 2>&1; shellbrain
|
|
231
|
+
Retry through `zsh -lc 'source ~/.zprofile >/dev/null 2>&1; command -v shellbrain'` first. Do not keep prefixing every Shellbrain command with profile sourcing. Only if that still fails should you ask the operator to restore the one-time machine install.
|
|
232
232
|
|
|
233
233
|
- `shellbrain init` fails or `doctor` shows `repair_needed`
|
|
234
234
|
Rerun `shellbrain init`. That is the normal repair path.
|
|
@@ -27,10 +27,10 @@ Shellbrain has two layers:
|
|
|
27
27
|
2. Otherwise, do not rerun `init` just because a new agent session started. Start with focused `read` queries right away.
|
|
28
28
|
3. If readiness is unclear, inspect with `shellbrain admin doctor` instead of rerunning `init` by reflex.
|
|
29
29
|
4. If `doctor` reports `repair_needed`, rerun `shellbrain init`.
|
|
30
|
-
5. If direct `shellbrain` calls fail in the current Cursor shell,
|
|
31
|
-
- `zsh -lc 'source ~/.zprofile >/dev/null 2>&1; shellbrain
|
|
32
|
-
- `bash -lc 'source ~/.bash_profile >/dev/null 2>&1; shellbrain
|
|
33
|
-
6. If the
|
|
30
|
+
5. If direct `shellbrain` calls fail in the current Cursor shell, do a one-time login-shell retry that sources the user's login profile and resolves the CLI path:
|
|
31
|
+
- `zsh -lc 'source ~/.zprofile >/dev/null 2>&1; command -v shellbrain'`
|
|
32
|
+
- `bash -lc 'source ~/.bash_profile >/dev/null 2>&1; command -v shellbrain'`
|
|
33
|
+
6. Do not keep sourcing the login profile on every Shellbrain command. Once `shellbrain` is visible, use plain `shellbrain ...`. If the host tool keeps starting fresh shells without your login PATH, reuse the absolute path returned by `command -v shellbrain` instead of re-sourcing the profile on every call. If the one-time login-shell retry still cannot find `shellbrain`, inspect Python's user script directory:
|
|
34
34
|
- `python3 -c "import sysconfig; print(sysconfig.get_path('scripts', 'posix_user'))"`
|
|
35
35
|
7. Resolve the target repo:
|
|
36
36
|
- use the current working directory when already inside the repo
|
|
@@ -124,35 +124,6 @@ def save_repo_registration(registration: RepoRegistration, repo_root: Path) -> P
|
|
|
124
124
|
return path
|
|
125
125
|
|
|
126
126
|
|
|
127
|
-
def register_repo(
|
|
128
|
-
*,
|
|
129
|
-
repo_root: Path,
|
|
130
|
-
machine_instance_id: str,
|
|
131
|
-
explicit_repo_id: str | None = None,
|
|
132
|
-
claude_status: str = "not_checked",
|
|
133
|
-
claude_settings_path: str | None = None,
|
|
134
|
-
claude_note: str | None = None,
|
|
135
|
-
) -> RepoRegistration:
|
|
136
|
-
"""Resolve and persist one repo registration."""
|
|
137
|
-
|
|
138
|
-
identity = resolve_repo_identity(repo_root=repo_root, explicit_repo_id=explicit_repo_id)
|
|
139
|
-
registration_root = Path(identity.git_root).resolve() if identity.git_root is not None else Path(repo_root).resolve()
|
|
140
|
-
registration = RepoRegistration(
|
|
141
|
-
repo_state_version=REPO_STATE_VERSION,
|
|
142
|
-
repo_id=identity.repo_id,
|
|
143
|
-
identity_strength=identity.identity_strength,
|
|
144
|
-
git_root=identity.git_root,
|
|
145
|
-
source_remote=identity.source_remote,
|
|
146
|
-
registered_at=datetime.now(timezone.utc).isoformat(),
|
|
147
|
-
machine_instance_id=machine_instance_id,
|
|
148
|
-
claude_status=claude_status,
|
|
149
|
-
claude_settings_path=claude_settings_path,
|
|
150
|
-
claude_note=claude_note,
|
|
151
|
-
)
|
|
152
|
-
save_repo_registration(registration, registration_root)
|
|
153
|
-
return registration
|
|
154
|
-
|
|
155
|
-
|
|
156
127
|
def register_repo_for_target(
|
|
157
128
|
*,
|
|
158
129
|
repo_root: Path,
|
|
@@ -8,6 +8,7 @@ from app.core.contracts.errors import ErrorCode, ErrorDetail
|
|
|
8
8
|
from app.core.contracts.requests import (
|
|
9
9
|
BatchUtilityVoteItem,
|
|
10
10
|
EpisodeEventsRequest,
|
|
11
|
+
MemoryKindValue,
|
|
11
12
|
MemoryBatchUpdateRequest,
|
|
12
13
|
MemoryCreateLinks,
|
|
13
14
|
MemoryCreateRequest,
|
|
@@ -27,17 +28,15 @@ class AgentReadRequest(StrictBaseModel):
|
|
|
27
28
|
mode: Literal["ambient", "targeted"] | None = None
|
|
28
29
|
query: str = Field(min_length=1)
|
|
29
30
|
include_global: bool | None = None
|
|
30
|
-
kinds: (
|
|
31
|
-
list[Literal["problem", "solution", "failed_tactic", "fact", "preference", "change"]] | None
|
|
32
|
-
) = None
|
|
31
|
+
kinds: list[MemoryKindValue] | None = Field(default=None, min_length=1)
|
|
33
32
|
limit: int | None = Field(default=None, ge=1, le=100)
|
|
34
33
|
|
|
35
34
|
@field_validator("kinds")
|
|
36
35
|
@classmethod
|
|
37
36
|
def _validate_kinds_unique(
|
|
38
37
|
cls,
|
|
39
|
-
value: list[
|
|
40
|
-
) -> list[
|
|
38
|
+
value: list[MemoryKindValue] | None,
|
|
39
|
+
) -> list[MemoryKindValue] | None:
|
|
41
40
|
"""This validator enforces unique kinds filters for agent read requests."""
|
|
42
41
|
|
|
43
42
|
if value is None:
|
|
@@ -52,7 +51,7 @@ class AgentCreateBody(StrictBaseModel):
|
|
|
52
51
|
|
|
53
52
|
text: str
|
|
54
53
|
scope: Literal["repo", "global"] | None = None
|
|
55
|
-
kind:
|
|
54
|
+
kind: MemoryKindValue
|
|
56
55
|
rationale: str | None = None
|
|
57
56
|
links: MemoryCreateLinks = Field(default_factory=MemoryCreateLinks)
|
|
58
57
|
evidence_refs: list[str] = Field(min_length=1)
|
{shellbrain-0.1.20 → shellbrain-0.1.22}/app/periphery/db/repos/relational/read_policy_repo.py
RENAMED
|
@@ -150,7 +150,24 @@ class ReadPolicyRepo(IReadPolicyRepo):
|
|
|
150
150
|
*self._visibility_filters(repo_id=repo_id, include_global=include_global, kinds=kinds),
|
|
151
151
|
)
|
|
152
152
|
)
|
|
153
|
-
|
|
153
|
+
reverse_matures_into_stmt = (
|
|
154
|
+
select(
|
|
155
|
+
association_edges.c.from_memory_id.label("memory_id"),
|
|
156
|
+
association_edges.c.relation_type,
|
|
157
|
+
association_edges.c.strength,
|
|
158
|
+
literal("association").label("expansion_type"),
|
|
159
|
+
)
|
|
160
|
+
.select_from(association_edges.join(memories, memories.c.id == association_edges.c.from_memory_id))
|
|
161
|
+
.where(
|
|
162
|
+
association_edges.c.repo_id == repo_id,
|
|
163
|
+
association_edges.c.to_memory_id == anchor_memory_id,
|
|
164
|
+
association_edges.c.relation_type == "matures_into",
|
|
165
|
+
association_edges.c.state != "deprecated",
|
|
166
|
+
association_edges.c.strength >= min_strength,
|
|
167
|
+
*self._visibility_filters(repo_id=repo_id, include_global=include_global, kinds=kinds),
|
|
168
|
+
)
|
|
169
|
+
)
|
|
170
|
+
union_stmt = union_all(from_stmt, reverse_associated_stmt, reverse_matures_into_stmt).subquery()
|
|
154
171
|
stmt = (
|
|
155
172
|
select(
|
|
156
173
|
union_stmt.c.memory_id,
|
|
@@ -46,17 +46,6 @@ def detect_claude_runtime_without_hook() -> bool:
|
|
|
46
46
|
)
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
def detect_claude_runtime_signal() -> bool:
|
|
50
|
-
"""Return whether one real Claude runtime signal is present in the current environment."""
|
|
51
|
-
|
|
52
|
-
if os.getenv("SHELLBRAIN_HOST_APP") == "claude_code":
|
|
53
|
-
return True
|
|
54
|
-
return any(
|
|
55
|
-
os.getenv(name)
|
|
56
|
-
for name in ("CLAUDE_SESSION_ID", "CLAUDE_CODE_REMOTE_SESSION_ID", "CLAUDE_CODE_AGENT_NAME")
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
|
|
60
49
|
def resolve_trusted_claude_transcript_path() -> Path | None:
|
|
61
50
|
"""Return the trusted Claude transcript path injected by the Shellbrain hook when present."""
|
|
62
51
|
|
|
@@ -31,8 +31,3 @@ def host_identity_drifted_error(*, caller_id: str) -> ErrorDetail:
|
|
|
31
31
|
message=f"Trusted caller identity drifted and could not be resolved for `{caller_id}`. Verify the host thread/session still exists and rerun `events`.",
|
|
32
32
|
)
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
def transcript_source_not_found_error(*, message: str) -> ErrorDetail:
|
|
36
|
-
"""Return the canonical error for transcript-source resolution failures."""
|
|
37
|
-
|
|
38
|
-
return ErrorDetail(code=ErrorCode.TRANSCRIPT_SOURCE_NOT_FOUND, message=message)
|