From 0f5ef0be63f5fe967cf931cf9aba2b19f6f2e4ca Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Thu, 22 Oct 2026 10:50:45 -0400 Subject: [PATCH] =?UTF-8?q?rename(547):=20the=20server=20is=20grimoire=20?= =?UTF-8?q?=E2=80=94=20package,=20image,=20DB=20defaults,=20backups?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Step 2 of the Scribe -> Grimoire rename. - src/scribe -> src/grimoire, and every import, patch target, module path, hypercorn entry point and `python -m grimoire.restore` with it; pyproject, uv.lock and the frontend package are named grimoire. - Image git.fabledsword.com/bvandeusen/fabledgrimoire; CI's Postgres service runs as grimoire / grimoire_test. - Compose files default the DB user, database and (prod) volume to grimoire, each overridable from .env, so an install created as Scribe keeps its data by setting POSTGRES_USER, POSTGRES_DB and PGDATA_VOLUME. - Backups are written as grimoire-.tar with format grimoire-backup-tar. Archives named scribe-* with the scribe-backup-tar manifest still restore and are still counted at the destination (folder and S3), with tests. - Exports, the MCP auth realm, the ASGI scope key and the persistent logger carry the new name. Kept on purpose: the secret-sealing key label stays "scribe.secrets.v1", because every stored secret was derived under it. Plugin identity (plugin name, hooks, env vars, .scribe marker, skills) is step 3. Co-Authored-By: Claude Opus 5.5 --- .env.example | 5 +- .forgejo/workflows/ci.yml | 10 +- Dockerfile | 4 +- alembic/env.py | 6 +- alembic/versions/0122_seal_forge_tokens.py | 2 +- docker-compose.prod.yml | 15 +- docker-compose.quickstart.yml | 10 +- docker-compose.yml | 8 +- docs/api-keys-and-mcp.md | 6 +- docs/api-reference.md | 2 +- docs/architecture.md | 10 +- docs/backups.md | 19 ++- docs/configuration.md | 8 +- docs/development.md | 2 +- docs/features.md | 2 +- frontend/package-lock.json | 4 +- frontend/package.json | 2 +- frontend/src/api/version.ts | 2 +- .../src/components/BackupScheduleSettings.vue | 4 +- frontend/src/views/SettingsView.vue | 6 +- pyproject.toml | 2 +- scripts/import_fabledrulebook.py | 2 +- src/{scribe => grimoire}/__init__.py | 0 src/{scribe => grimoire}/app.py | 104 ++++++------ src/{scribe => grimoire}/auth.py | 4 +- src/{scribe => grimoire}/config.py | 2 +- src/{scribe => grimoire}/mcp/__init__.py | 2 +- src/{scribe => grimoire}/mcp/_context.py | 4 +- src/{scribe => grimoire}/mcp/auth.py | 2 +- src/{scribe => grimoire}/mcp/server.py | 12 +- .../mcp/tools/__init__.py | 2 +- .../mcp/tools/design_systems.py | 8 +- src/{scribe => grimoire}/mcp/tools/family.py | 6 +- src/{scribe => grimoire}/mcp/tools/lessons.py | 22 +-- .../mcp/tools/milestones.py | 20 +-- src/{scribe => grimoire}/mcp/tools/moments.py | 10 +- src/{scribe => grimoire}/mcp/tools/notes.py | 24 +-- .../mcp/tools/platforms.py | 4 +- .../mcp/tools/processes.py | 22 +-- .../mcp/tools/projects.py | 32 ++-- src/{scribe => grimoire}/mcp/tools/recent.py | 8 +- src/{scribe => grimoire}/mcp/tools/repos.py | 6 +- .../mcp/tools/retrieval_review.py | 4 +- .../mcp/tools/retrieval_tuning.py | 6 +- .../mcp/tools/rulebooks.py | 14 +- src/{scribe => grimoire}/mcp/tools/search.py | 16 +- src/{scribe => grimoire}/mcp/tools/shapes.py | 6 +- .../mcp/tools/snippets.py | 20 +-- src/{scribe => grimoire}/mcp/tools/systems.py | 14 +- src/{scribe => grimoire}/mcp/tools/tags.py | 6 +- src/{scribe => grimoire}/mcp/tools/tasks.py | 40 ++--- src/{scribe => grimoire}/mcp/tools/trash.py | 4 +- .../mcp/tools/wide_net.py | 6 +- src/{scribe => grimoire}/models/__init__.py | 74 ++++----- src/{scribe => grimoire}/models/api_key.py | 4 +- src/{scribe => grimoire}/models/app_log.py | 4 +- src/{scribe => grimoire}/models/base.py | 0 .../models/canonical_system.py | 4 +- src/{scribe => grimoire}/models/code_shape.py | 4 +- .../models/design_system.py | 4 +- src/{scribe => grimoire}/models/embedding.py | 2 +- src/{scribe => grimoire}/models/family.py | 4 +- .../models/forge_connection.py | 4 +- src/{scribe => grimoire}/models/group.py | 4 +- src/{scribe => grimoire}/models/invitation.py | 4 +- .../models/lesson_rule_link.py | 4 +- src/{scribe => grimoire}/models/milestone.py | 4 +- .../models/moment_mapping.py | 4 +- src/{scribe => grimoire}/models/note.py | 6 +- src/{scribe => grimoire}/models/note_draft.py | 4 +- .../models/note_supersession.py | 4 +- src/{scribe => grimoire}/models/note_usage.py | 4 +- .../models/note_version.py | 4 +- .../models/notification.py | 4 +- .../models/password_reset.py | 4 +- src/{scribe => grimoire}/models/project.py | 4 +- .../models/repo_binding.py | 4 +- .../models/retrieval_judgment.py | 4 +- .../models/retrieval_log.py | 4 +- .../models/retrieval_tuning.py | 2 +- .../models/rule_moment_judgment.py | 6 +- src/{scribe => grimoire}/models/rule_usage.py | 4 +- .../models/rule_version.py | 4 +- src/{scribe => grimoire}/models/rulebook.py | 4 +- src/{scribe => grimoire}/models/setting.py | 2 +- src/{scribe => grimoire}/models/share.py | 4 +- src/{scribe => grimoire}/models/system.py | 4 +- .../models/system_usage.py | 4 +- src/{scribe => grimoire}/models/task_log.py | 4 +- src/{scribe => grimoire}/models/user.py | 4 +- src/{scribe => grimoire}/rate_limit.py | 0 src/{scribe => grimoire}/restore.py | 16 +- src/{scribe => grimoire}/routes/__init__.py | 0 src/{scribe => grimoire}/routes/admin.py | 44 ++--- src/{scribe => grimoire}/routes/api.py | 0 src/{scribe => grimoire}/routes/api_keys.py | 4 +- src/{scribe => grimoire}/routes/auth.py | 16 +- .../routes/canonical_systems.py | 8 +- src/{scribe => grimoire}/routes/dashboard.py | 4 +- .../routes/design_systems.py | 10 +- src/{scribe => grimoire}/routes/export.py | 10 +- src/{scribe => grimoire}/routes/family.py | 8 +- src/{scribe => grimoire}/routes/groups.py | 6 +- .../routes/in_app_notifications.py | 4 +- src/{scribe => grimoire}/routes/knowledge.py | 20 +-- src/{scribe => grimoire}/routes/lessons.py | 20 +-- src/{scribe => grimoire}/routes/milestones.py | 14 +- src/{scribe => grimoire}/routes/notes.py | 28 ++-- src/{scribe => grimoire}/routes/platforms.py | 6 +- src/{scribe => grimoire}/routes/plugin.py | 32 ++-- src/{scribe => grimoire}/routes/projects.py | 24 +-- src/{scribe => grimoire}/routes/retrieval.py | 16 +- src/{scribe => grimoire}/routes/rulebooks.py | 10 +- src/{scribe => grimoire}/routes/search.py | 12 +- src/{scribe => grimoire}/routes/settings.py | 24 +-- src/{scribe => grimoire}/routes/shares.py | 10 +- src/{scribe => grimoire}/routes/snippets.py | 16 +- src/{scribe => grimoire}/routes/systems.py | 12 +- src/{scribe => grimoire}/routes/task_logs.py | 6 +- src/{scribe => grimoire}/routes/tasks.py | 26 +-- src/{scribe => grimoire}/routes/trash.py | 4 +- src/{scribe => grimoire}/routes/users.py | 6 +- src/{scribe => grimoire}/routes/utils.py | 0 src/{scribe => grimoire}/routes/webhooks.py | 14 +- src/{scribe => grimoire}/services/__init__.py | 0 src/{scribe => grimoire}/services/access.py | 16 +- src/{scribe => grimoire}/services/api_keys.py | 4 +- src/{scribe => grimoire}/services/auth.py | 20 +-- .../services/background.py | 2 +- src/{scribe => grimoire}/services/backup.py | 52 +++--- .../services/backup_destination.py | 23 +-- .../services/backup_file.py | 19 ++- .../services/backup_job.py | 8 +- .../services/backup_s3.py | 0 .../services/canonical_systems.py | 8 +- src/{scribe => grimoire}/services/coverage.py | 28 ++-- .../services/dashboard.py | 12 +- .../services/db_maintenance.py | 6 +- .../services/db_maintenance_scheduler.py | 6 +- src/{scribe => grimoire}/services/db_ready.py | 0 src/{scribe => grimoire}/services/dedup.py | 34 ++-- .../services/design_cascade.py | 0 .../services/design_starter_roles.py | 0 .../services/design_stylesheet.py | 0 .../services/design_systems.py | 16 +- .../services/diagnostics.py | 4 +- src/{scribe => grimoire}/services/email.py | 8 +- .../services/embeddings.py | 58 +++---- src/{scribe => grimoire}/services/family.py | 24 +-- .../services/family_adoption.py | 28 ++-- src/{scribe => grimoire}/services/forge.py | 14 +- .../services/forge_connections.py | 10 +- src/{scribe => grimoire}/services/groups.py | 6 +- .../services/inception.py | 24 +-- .../services/knowledge.py | 14 +- .../services/lesson_rules.py | 44 ++--- src/{scribe => grimoire}/services/lessons.py | 16 +- src/{scribe => grimoire}/services/logging.py | 8 +- .../services/milestones.py | 10 +- .../services/moment_actions.py | 10 +- .../services/moment_delivery.py | 14 +- src/{scribe => grimoire}/services/moments.py | 0 .../services/note_drafts.py | 4 +- .../services/note_usage.py | 10 +- .../services/note_versions.py | 4 +- src/{scribe => grimoire}/services/notes.py | 46 +++--- .../services/notifications.py | 28 ++-- src/{scribe => grimoire}/services/oauth.py | 6 +- .../services/placement.py | 12 +- src/{scribe => grimoire}/services/planning.py | 12 +- .../services/platforms.py | 8 +- .../services/plugin_context.py | 46 +++--- src/{scribe => grimoire}/services/projects.py | 16 +- .../services/record_batch.py | 16 +- .../services/record_refs.py | 4 +- .../services/recurrence.py | 6 +- .../services/recurrence_scheduler.py | 4 +- .../services/reply_shapes.py | 12 +- .../services/repo_bindings.py | 4 +- .../services/report_check.py | 6 +- .../services/retrieval_migration.py | 12 +- .../services/retrieval_pipeline.py | 8 +- .../services/retrieval_registry.py | 16 +- .../services/retrieval_review.py | 18 +- .../services/retrieval_surfaces.py | 4 +- .../services/retrieval_telemetry.py | 48 +++--- .../services/retrieval_tuning.py | 10 +- .../services/rule_moment_judgments.py | 22 +-- .../services/rule_scope.py | 10 +- .../services/rule_usage.py | 10 +- .../services/rule_versions.py | 4 +- .../services/rulebooks.py | 64 ++++---- .../services/scheduler.py | 0 src/{scribe => grimoire}/services/secrets.py | 4 +- src/{scribe => grimoire}/services/settings.py | 6 +- .../services/shape_check.py | 4 +- .../services/shape_ledger.py | 56 +++---- src/{scribe => grimoire}/services/sharing.py | 28 ++-- src/{scribe => grimoire}/services/snippets.py | 34 ++-- .../services/supersession.py | 8 +- .../services/system_rulings.py | 6 +- .../services/system_usage.py | 8 +- src/{scribe => grimoire}/services/systems.py | 12 +- .../services/task_claims.py | 22 +-- .../services/task_logs.py | 12 +- src/{scribe => grimoire}/services/text.py | 0 src/{scribe => grimoire}/services/trash.py | 12 +- .../services/trash_scheduler.py | 10 +- src/{scribe => grimoire}/services/tz.py | 2 +- .../services/verification.py | 0 .../services/version_pinning.py | 6 +- .../services/version_pinning_scheduler.py | 4 +- src/{scribe => grimoire}/static/.gitkeep | 0 src/{scribe => grimoire}/utils/__init__.py | 0 src/{scribe => grimoire}/utils/tags.py | 0 tests/conftest.py | 58 +++---- tests/helpers.py | 22 +-- tests/test_api_keys.py | 20 +-- tests/test_autoinject_context.py | 4 +- tests/test_backfill_reads_current_text.py | 2 +- tests/test_calibration_stamp.py | 10 +- tests/test_chunking.py | 16 +- tests/test_cited_record_status.py | 14 +- tests/test_create_tools_disambiguate.py | 16 +- tests/test_db_ready.py | 2 +- tests/test_derived_mirror_generic_door.py | 32 ++-- tests/test_design_cascade.py | 2 +- tests/test_design_starter_roles.py | 2 +- tests/test_design_stylesheet.py | 2 +- tests/test_divergence_meaning_gate.py | 10 +- tests/test_embedding_text.py | 4 +- tests/test_embedding_yields_to_a_delete.py | 2 +- tests/test_embeddings.py | 16 +- tests/test_family.py | 14 +- tests/test_family_adoption.py | 8 +- tests/test_family_delivery.py | 14 +- tests/test_family_models.py | 4 +- tests/test_family_shapes.py | 14 +- tests/test_forge_token_sealing.py | 4 +- tests/test_forge_webhook.py | 22 +-- tests/test_gate_settings.py | 14 +- tests/test_guidance_ownership.py | 8 +- tests/test_inception.py | 6 +- tests/test_instruction_surfaces_agree.py | 4 +- ...integration_backup_code_shape_roundtrip.py | 12 +- .../test_integration_backup_file_ordering.py | 10 +- tests/test_integration_backup_file_restore.py | 18 +- .../test_integration_backup_note_roundtrip.py | 8 +- ...integration_backup_rule_usage_roundtrip.py | 12 +- ...tegration_backup_rule_version_roundtrip.py | 10 +- tests/test_integration_db_maintenance.py | 2 +- ..._integration_embedding_yields_to_delete.py | 12 +- tests/test_integration_family_adoption.py | 40 ++--- tests/test_integration_family_canon.py | 12 +- tests/test_integration_family_promotion.py | 24 +-- tests/test_integration_family_reach.py | 16 +- tests/test_integration_forge_keyring.py | 12 +- tests/test_integration_handshake_touched.py | 14 +- tests/test_integration_inception.py | 10 +- tests/test_integration_lesson_kind.py | 8 +- tests/test_integration_lesson_reach.py | 14 +- tests/test_integration_lesson_rule_links.py | 20 +-- tests/test_integration_milestone_search.py | 16 +- tests/test_integration_moment_mappings.py | 6 +- tests/test_integration_pgvector_search.py | 16 +- tests/test_integration_placement.py | 14 +- tests/test_integration_platforms.py | 10 +- tests/test_integration_preference_drift.py | 10 +- tests/test_integration_record_batch.py | 14 +- tests/test_integration_rule_kind.py | 6 +- .../test_integration_rule_moment_judgments.py | 14 +- tests/test_integration_rule_moments.py | 24 +-- tests/test_integration_rule_move.py | 14 +- tests/test_integration_rule_scope.py | 20 +-- tests/test_integration_rule_surfacing.py | 10 +- tests/test_integration_rule_verification.py | 6 +- tests/test_integration_rule_versions.py | 10 +- tests/test_integration_search_scope.py | 22 +-- tests/test_integration_shape_classify.py | 82 +++++----- tests/test_integration_snippet_locations.py | 14 +- tests/test_integration_task_kind_spike.py | 8 +- tests/test_knowledge_facets.py | 4 +- tests/test_ledger_references_not_silence.py | 4 +- tests/test_lesson_claim.py | 16 +- tests/test_lesson_convergence.py | 10 +- tests/test_lesson_document_shape.py | 4 +- tests/test_lesson_insight_round_trip.py | 2 +- tests/test_lesson_kind.py | 10 +- tests/test_lesson_rest_door.py | 38 ++--- tests/test_lesson_rule_link_doors.py | 20 +-- tests/test_lesson_rule_link_ui.py | 12 +- tests/test_lesson_rule_soft_links.py | 8 +- tests/test_lesson_surfacing.py | 4 +- tests/test_lesson_usage_surface.py | 8 +- tests/test_lesson_write_path.py | 24 +-- tests/test_list_rows_brief.py | 18 +- tests/test_matched_passage_surfaces.py | 4 +- tests/test_mcp_auth.py | 20 +-- tests/test_mcp_context.py | 2 +- tests/test_mcp_endpoint.py | 6 +- tests/test_mcp_list_family.py | 2 +- tests/test_mcp_strict_args.py | 6 +- tests/test_mcp_tool_create_records.py | 74 ++++----- tests/test_mcp_tool_design_systems.py | 68 ++++---- tests/test_mcp_tool_milestones.py | 42 ++--- tests/test_mcp_tool_notes.py | 72 ++++---- tests/test_mcp_tool_planning.py | 32 ++-- tests/test_mcp_tool_processes.py | 92 +++++------ tests/test_mcp_tool_projects.py | 112 ++++++------- tests/test_mcp_tool_report_back_cue.py | 14 +- tests/test_mcp_tool_rulebooks.py | 154 +++++++++--------- tests/test_mcp_tool_search.py | 48 +++--- tests/test_mcp_tool_snippets.py | 78 ++++----- tests/test_mcp_tool_systems.py | 136 ++++++++-------- tests/test_mcp_tool_tags.py | 6 +- tests/test_mcp_tool_tasks.py | 56 +++---- tests/test_mcp_tool_tasks_kind.py | 28 ++-- tests/test_mcp_tool_trash.py | 18 +- tests/test_milestone_summary_brief.py | 42 ++--- tests/test_moment_actions.py | 8 +- tests/test_moment_delivery.py | 22 +-- tests/test_moments.py | 14 +- tests/test_named_records.py | 4 +- tests/test_note_pipeline.py | 16 +- tests/test_note_usage.py | 28 ++-- tests/test_notes_description_field.py | 10 +- tests/test_pattern_coverage.py | 78 ++++----- tests/test_platforms.py | 8 +- tests/test_pre_act_checkpoint.py | 2 +- tests/test_preference_write_path.py | 16 +- tests/test_pull_telemetry.py | 8 +- tests/test_record_kind_surface.py | 6 +- tests/test_records_are_named_not_numbered.py | 2 +- tests/test_recurrence.py | 60 +++---- tests/test_reply_discipline.py | 2 +- tests/test_reply_moment.py | 16 +- tests/test_reply_shape_turn.py | 6 +- tests/test_reply_shapes.py | 24 +-- tests/test_reporting_back_skill.py | 6 +- tests/test_retrieval_migration.py | 6 +- tests/test_retrieval_miss_route.py | 2 +- tests/test_retrieval_query_scrubbing.py | 4 +- tests/test_retrieval_registry.py | 6 +- tests/test_retrieval_review.py | 24 +-- tests/test_retrieval_scopes.py | 30 ++-- tests/test_retrieval_specs.py | 8 +- tests/test_retrieval_surfaces.py | 8 +- tests/test_retrieval_tuning.py | 6 +- tests/test_retrieval_warnings.py | 8 +- tests/test_routes_dashboard.py | 6 +- tests/test_routes_db_maintenance.py | 10 +- tests/test_routes_design_systems.py | 16 +- tests/test_routes_family.py | 6 +- tests/test_routes_planning.py | 4 +- tests/test_routes_platforms.py | 4 +- tests/test_routes_retrieval_tuning.py | 30 ++-- tests/test_routes_rulebooks.py | 24 +-- tests/test_routes_snippets.py | 28 ++-- tests/test_routes_systems.py | 8 +- tests/test_routes_tasks_kind.py | 6 +- tests/test_routes_trash.py | 10 +- tests/test_rule_creation_asks_first.py | 4 +- tests/test_rule_hint_band.py | 2 +- tests/test_rule_moment_doors.py | 26 +-- tests/test_rule_moment_judgments.py | 8 +- tests/test_rule_moment_signal_hooks.py | 4 +- tests/test_rule_opened_ledger.py | 2 +- tests/test_rule_overlap_gate.py | 18 +- tests/test_rule_trigger_required.py | 2 +- tests/test_rule_usage_wiring.py | 78 ++++----- tests/test_rule_via_lesson.py | 10 +- tests/test_scribe_marker.py | 2 +- tests/test_search_route.py | 2 +- tests/test_search_scope_shape.py | 8 +- tests/test_services_access_visibility.py | 6 +- tests/test_services_backup.py | 54 +++--- tests/test_services_backup_destination.py | 41 +++-- tests/test_services_backup_file.py | 27 ++- tests/test_services_backup_job.py | 10 +- tests/test_services_backup_s3.py | 24 +-- tests/test_services_canonical_systems.py | 2 +- tests/test_services_dashboard.py | 10 +- tests/test_services_db_maintenance.py | 22 +-- tests/test_services_dedup.py | 106 ++++++------ tests/test_services_design_systems.py | 116 ++++++------- tests/test_services_forge.py | 20 +-- tests/test_services_knowledge_counts.py | 4 +- tests/test_services_notes.py | 6 +- tests/test_services_notes_process.py | 16 +- tests/test_services_notes_sweep.py | 14 +- tests/test_services_notes_task_kind.py | 10 +- tests/test_services_notes_verification.py | 8 +- tests/test_services_placement.py | 4 +- tests/test_services_planning.py | 14 +- tests/test_services_plugin_context.py | 86 +++++----- tests/test_services_project_summaries.py | 14 +- tests/test_services_record_refs.py | 4 +- tests/test_services_repo_bindings.py | 2 +- tests/test_services_report_check.py | 26 +-- tests/test_services_retrieval_telemetry.py | 110 ++++++------- tests/test_services_rule_embeddings.py | 2 +- tests/test_services_rule_usage.py | 12 +- tests/test_services_rulebooks.py | 90 +++++----- tests/test_services_shape_check.py | 18 +- tests/test_services_snippets.py | 4 +- tests/test_services_supersession.py | 30 ++-- tests/test_services_systems.py | 94 +++++------ tests/test_services_trash.py | 38 ++--- tests/test_settings_defaults_agree.py | 6 +- tests/test_shape_form_gate.py | 6 +- tests/test_shape_ledger.py | 92 +++++------ tests/test_shared_provenance.py | 18 +- tests/test_shared_write_access.py | 26 +-- tests/test_skill_moments.py | 4 +- tests/test_snippet_drift_check.py | 10 +- tests/test_snippet_duplicates.py | 12 +- tests/test_snippet_live_body.py | 14 +- tests/test_snippet_location_filter.py | 32 ++-- tests/test_snippet_merge_provenance.py | 10 +- tests/test_snippet_notes.py | 6 +- tests/test_snippet_provenance.py | 10 +- tests/test_snippet_unmerge.py | 18 +- tests/test_stamps_to_review.py | 24 +-- .../test_startup_survives_a_slow_database.py | 20 +-- tests/test_supersession_ranking.py | 8 +- tests/test_system_charter_search.py | 6 +- tests/test_system_rulings.py | 8 +- tests/test_system_tagging_door_parity.py | 2 +- tests/test_system_usage_readout.py | 26 +-- tests/test_task_claims.py | 12 +- tests/test_task_document_shape.py | 12 +- tests/test_task_work_log_surface.py | 66 ++++---- tests/test_timestamp_filters.py | 10 +- tests/test_trash_filtering.py | 20 +-- tests/test_trigger_shape_is_taught.py | 4 +- tests/test_tz_helpers.py | 8 +- tests/test_usage_attach_seam.py | 10 +- tests/test_utils.py | 2 +- tests/test_verification_guidance_survives.py | 6 +- tests/test_version_endpoint.py | 2 +- tests/test_version_pinning_pin_unpin.py | 24 +-- tests/test_version_pinning_prune.py | 8 +- tests/test_version_pinning_scan.py | 16 +- tests/test_wide_net.py | 12 +- tests/test_write_path_design_arm.py | 4 +- tests/test_write_path_trigger.py | 130 +++++++-------- uv.lock | 2 +- 447 files changed, 3611 insertions(+), 3558 deletions(-) rename src/{scribe => grimoire}/__init__.py (100%) rename src/{scribe => grimoire}/app.py (83%) rename src/{scribe => grimoire}/auth.py (95%) rename src/{scribe => grimoire}/config.py (98%) rename src/{scribe => grimoire}/mcp/__init__.py (83%) rename src/{scribe => grimoire}/mcp/_context.py (78%) rename src/{scribe => grimoire}/mcp/auth.py (94%) rename src/{scribe => grimoire}/mcp/server.py (98%) rename src/{scribe => grimoire}/mcp/tools/__init__.py (97%) rename src/{scribe => grimoire}/mcp/tools/design_systems.py (98%) rename src/{scribe => grimoire}/mcp/tools/family.py (99%) rename src/{scribe => grimoire}/mcp/tools/lessons.py (97%) rename src/{scribe => grimoire}/mcp/tools/milestones.py (94%) rename src/{scribe => grimoire}/mcp/tools/moments.py (97%) rename src/{scribe => grimoire}/mcp/tools/notes.py (97%) rename src/{scribe => grimoire}/mcp/tools/platforms.py (96%) rename src/{scribe => grimoire}/mcp/tools/processes.py (95%) rename src/{scribe => grimoire}/mcp/tools/projects.py (96%) rename src/{scribe => grimoire}/mcp/tools/recent.py (93%) rename src/{scribe => grimoire}/mcp/tools/repos.py (95%) rename src/{scribe => grimoire}/mcp/tools/retrieval_review.py (97%) rename src/{scribe => grimoire}/mcp/tools/retrieval_tuning.py (98%) rename src/{scribe => grimoire}/mcp/tools/rulebooks.py (99%) rename src/{scribe => grimoire}/mcp/tools/search.py (98%) rename src/{scribe => grimoire}/mcp/tools/shapes.py (99%) rename src/{scribe => grimoire}/mcp/tools/snippets.py (98%) rename src/{scribe => grimoire}/mcp/tools/systems.py (98%) rename src/{scribe => grimoire}/mcp/tools/tags.py (92%) rename src/{scribe => grimoire}/mcp/tools/tasks.py (97%) rename src/{scribe => grimoire}/mcp/tools/trash.py (94%) rename src/{scribe => grimoire}/mcp/tools/wide_net.py (97%) rename src/{scribe => grimoire}/models/__init__.py (50%) rename src/{scribe => grimoire}/models/api_key.py (94%) rename src/{scribe => grimoire}/models/app_log.py (96%) rename src/{scribe => grimoire}/models/base.py (100%) rename src/{scribe => grimoire}/models/canonical_system.py (95%) rename src/{scribe => grimoire}/models/code_shape.py (99%) rename src/{scribe => grimoire}/models/design_system.py (98%) rename src/{scribe => grimoire}/models/embedding.py (99%) rename src/{scribe => grimoire}/models/family.py (99%) rename src/{scribe => grimoire}/models/forge_connection.py (95%) rename src/{scribe => grimoire}/models/group.py (94%) rename src/{scribe => grimoire}/models/invitation.py (91%) rename src/{scribe => grimoire}/models/lesson_rule_link.py (98%) rename src/{scribe => grimoire}/models/milestone.py (93%) rename src/{scribe => grimoire}/models/moment_mapping.py (97%) rename src/{scribe => grimoire}/models/note.py (98%) rename src/{scribe => grimoire}/models/note_draft.py (92%) rename src/{scribe => grimoire}/models/note_supersession.py (97%) rename src/{scribe => grimoire}/models/note_usage.py (98%) rename src/{scribe => grimoire}/models/note_version.py (93%) rename src/{scribe => grimoire}/models/notification.py (92%) rename src/{scribe => grimoire}/models/password_reset.py (90%) rename src/{scribe => grimoire}/models/project.py (96%) rename src/{scribe => grimoire}/models/repo_binding.py (95%) rename src/{scribe => grimoire}/models/retrieval_judgment.py (97%) rename src/{scribe => grimoire}/models/retrieval_log.py (98%) rename src/{scribe => grimoire}/models/retrieval_tuning.py (99%) rename src/{scribe => grimoire}/models/rule_moment_judgment.py (95%) rename src/{scribe => grimoire}/models/rule_usage.py (98%) rename src/{scribe => grimoire}/models/rule_version.py (98%) rename src/{scribe => grimoire}/models/rulebook.py (98%) rename src/{scribe => grimoire}/models/setting.py (93%) rename src/{scribe => grimoire}/models/share.py (96%) rename src/{scribe => grimoire}/models/system.py (97%) rename src/{scribe => grimoire}/models/system_usage.py (96%) rename src/{scribe => grimoire}/models/task_log.py (91%) rename src/{scribe => grimoire}/models/user.py (92%) rename src/{scribe => grimoire}/rate_limit.py (100%) rename src/{scribe => grimoire}/restore.py (87%) rename src/{scribe => grimoire}/routes/__init__.py (100%) rename src/{scribe => grimoire}/routes/admin.py (92%) rename src/{scribe => grimoire}/routes/api.py (100%) rename src/{scribe => grimoire}/routes/api_keys.py (89%) rename src/{scribe => grimoire}/routes/auth.py (97%) rename src/{scribe => grimoire}/routes/canonical_systems.py (93%) rename src/{scribe => grimoire}/routes/dashboard.py (75%) rename src/{scribe => grimoire}/routes/design_systems.py (97%) rename src/{scribe => grimoire}/routes/export.py (92%) rename src/{scribe => grimoire}/routes/family.py (95%) rename src/{scribe => grimoire}/routes/groups.py (95%) rename src/{scribe => grimoire}/routes/in_app_notifications.py (92%) rename src/{scribe => grimoire}/routes/knowledge.py (90%) rename src/{scribe => grimoire}/routes/lessons.py (96%) rename src/{scribe => grimoire}/routes/milestones.py (93%) rename src/{scribe => grimoire}/routes/notes.py (96%) rename src/{scribe => grimoire}/routes/platforms.py (95%) rename src/{scribe => grimoire}/routes/plugin.py (97%) rename src/{scribe => grimoire}/routes/projects.py (94%) rename src/{scribe => grimoire}/routes/retrieval.py (94%) rename src/{scribe => grimoire}/routes/rulebooks.py (98%) rename src/{scribe => grimoire}/routes/search.py (89%) rename src/{scribe => grimoire}/routes/settings.py (91%) rename src/{scribe => grimoire}/routes/shares.py (93%) rename src/{scribe => grimoire}/routes/snippets.py (97%) rename src/{scribe => grimoire}/routes/systems.py (95%) rename src/{scribe => grimoire}/routes/task_logs.py (91%) rename src/{scribe => grimoire}/routes/tasks.py (93%) rename src/{scribe => grimoire}/routes/trash.py (87%) rename src/{scribe => grimoire}/routes/users.py (84%) rename src/{scribe => grimoire}/routes/utils.py (100%) rename src/{scribe => grimoire}/routes/webhooks.py (93%) rename src/{scribe => grimoire}/services/__init__.py (100%) rename src/{scribe => grimoire}/services/access.py (97%) rename src/{scribe => grimoire}/services/api_keys.py (97%) rename src/{scribe => grimoire}/services/auth.py (96%) rename src/{scribe => grimoire}/services/background.py (98%) rename src/{scribe => grimoire}/services/backup.py (98%) rename src/{scribe => grimoire}/services/backup_destination.py (93%) rename src/{scribe => grimoire}/services/backup_file.py (92%) rename src/{scribe => grimoire}/services/backup_job.py (96%) rename src/{scribe => grimoire}/services/backup_s3.py (100%) rename src/{scribe => grimoire}/services/canonical_systems.py (98%) rename src/{scribe => grimoire}/services/coverage.py (98%) rename src/{scribe => grimoire}/services/dashboard.py (96%) rename src/{scribe => grimoire}/services/db_maintenance.py (97%) rename src/{scribe => grimoire}/services/db_maintenance_scheduler.py (96%) rename src/{scribe => grimoire}/services/db_ready.py (100%) rename src/{scribe => grimoire}/services/dedup.py (98%) rename src/{scribe => grimoire}/services/design_cascade.py (100%) rename src/{scribe => grimoire}/services/design_starter_roles.py (100%) rename src/{scribe => grimoire}/services/design_stylesheet.py (100%) rename src/{scribe => grimoire}/services/design_systems.py (98%) rename src/{scribe => grimoire}/services/diagnostics.py (99%) rename src/{scribe => grimoire}/services/email.py (97%) rename src/{scribe => grimoire}/services/embeddings.py (98%) rename src/{scribe => grimoire}/services/family.py (98%) rename src/{scribe => grimoire}/services/family_adoption.py (98%) rename src/{scribe => grimoire}/services/forge.py (98%) rename src/{scribe => grimoire}/services/forge_connections.py (96%) rename src/{scribe => grimoire}/services/groups.py (97%) rename src/{scribe => grimoire}/services/inception.py (94%) rename src/{scribe => grimoire}/services/knowledge.py (98%) rename src/{scribe => grimoire}/services/lesson_rules.py (96%) rename src/{scribe => grimoire}/services/lessons.py (98%) rename src/{scribe => grimoire}/services/logging.py (97%) rename src/{scribe => grimoire}/services/milestones.py (98%) rename src/{scribe => grimoire}/services/moment_actions.py (98%) rename src/{scribe => grimoire}/services/moment_delivery.py (97%) rename src/{scribe => grimoire}/services/moments.py (100%) rename src/{scribe => grimoire}/services/note_drafts.py (95%) rename src/{scribe => grimoire}/services/note_usage.py (98%) rename src/{scribe => grimoire}/services/note_versions.py (97%) rename src/{scribe => grimoire}/services/notes.py (97%) rename src/{scribe => grimoire}/services/notifications.py (96%) rename src/{scribe => grimoire}/services/oauth.py (97%) rename src/{scribe => grimoire}/services/placement.py (95%) rename src/{scribe => grimoire}/services/planning.py (90%) rename src/{scribe => grimoire}/services/platforms.py (98%) rename src/{scribe => grimoire}/services/plugin_context.py (98%) rename src/{scribe => grimoire}/services/projects.py (95%) rename src/{scribe => grimoire}/services/record_batch.py (94%) rename src/{scribe => grimoire}/services/record_refs.py (99%) rename src/{scribe => grimoire}/services/recurrence.py (97%) rename src/{scribe => grimoire}/services/recurrence_scheduler.py (90%) rename src/{scribe => grimoire}/services/reply_shapes.py (98%) rename src/{scribe => grimoire}/services/repo_bindings.py (98%) rename src/{scribe => grimoire}/services/report_check.py (97%) rename src/{scribe => grimoire}/services/retrieval_migration.py (97%) rename src/{scribe => grimoire}/services/retrieval_pipeline.py (99%) rename src/{scribe => grimoire}/services/retrieval_registry.py (96%) rename src/{scribe => grimoire}/services/retrieval_review.py (96%) rename src/{scribe => grimoire}/services/retrieval_surfaces.py (97%) rename src/{scribe => grimoire}/services/retrieval_telemetry.py (98%) rename src/{scribe => grimoire}/services/retrieval_tuning.py (98%) rename src/{scribe => grimoire}/services/rule_moment_judgments.py (97%) rename src/{scribe => grimoire}/services/rule_scope.py (88%) rename src/{scribe => grimoire}/services/rule_usage.py (98%) rename src/{scribe => grimoire}/services/rule_versions.py (97%) rename src/{scribe => grimoire}/services/rulebooks.py (97%) rename src/{scribe => grimoire}/services/scheduler.py (100%) rename src/{scribe => grimoire}/services/secrets.py (89%) rename src/{scribe => grimoire}/services/settings.py (97%) rename src/{scribe => grimoire}/services/shape_check.py (98%) rename src/{scribe => grimoire}/services/shape_ledger.py (98%) rename src/{scribe => grimoire}/services/sharing.py (92%) rename src/{scribe => grimoire}/services/snippets.py (98%) rename src/{scribe => grimoire}/services/supersession.py (97%) rename src/{scribe => grimoire}/services/system_rulings.py (97%) rename src/{scribe => grimoire}/services/system_usage.py (95%) rename src/{scribe => grimoire}/services/systems.py (98%) rename src/{scribe => grimoire}/services/task_claims.py (96%) rename src/{scribe => grimoire}/services/task_logs.py (95%) rename src/{scribe => grimoire}/services/text.py (100%) rename src/{scribe => grimoire}/services/trash.py (97%) rename src/{scribe => grimoire}/services/trash_scheduler.py (84%) rename src/{scribe => grimoire}/services/tz.py (97%) rename src/{scribe => grimoire}/services/verification.py (100%) rename src/{scribe => grimoire}/services/version_pinning.py (98%) rename src/{scribe => grimoire}/services/version_pinning_scheduler.py (90%) rename src/{scribe => grimoire}/static/.gitkeep (100%) rename src/{scribe => grimoire}/utils/__init__.py (100%) rename src/{scribe => grimoire}/utils/tags.py (100%) diff --git a/.env.example b/.env.example index f62c5394..897c1f55 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,7 @@ +# An install created before the rename from Scribe keeps its database by +# setting these, and PGDATA_VOLUME, to the names it was created with. POSTGRES_USER=fabled POSTGRES_PASSWORD=fabled -POSTGRES_DB=scribe +POSTGRES_DB=grimoire +# PGDATA_VOLUME=grimoire_pgdata SECRET_KEY=dev-secret-change-me diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 9609e3ff..697a5621 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -55,7 +55,7 @@ permissions: env: REGISTRY: git.fabledsword.com - IMAGE: git.fabledsword.com/bvandeusen/fabledscribe + IMAGE: git.fabledsword.com/bvandeusen/fabledgrimoire jobs: typecheck: @@ -193,11 +193,11 @@ jobs: # Same image as the shipped compose files: Postgres 17 with pgvector. image: pgvector/pgvector:pg17 env: - POSTGRES_USER: scribe + POSTGRES_USER: grimoire POSTGRES_PASSWORD: ci_integration - POSTGRES_DB: scribe_test + POSTGRES_DB: grimoire_test options: >- - --health-cmd "pg_isready -U scribe" + --health-cmd "pg_isready -U grimoire" --health-interval 10s --health-timeout 5s --health-retries 10 @@ -235,7 +235,7 @@ jobs: test "$(printf '%s\n' "$PG" | grep -c .)" -eq 1 PG_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$PG") test -n "$PG_IP" - export DATABASE_URL="postgresql+asyncpg://scribe:ci_integration@${PG_IP}:5432/scribe_test" + export DATABASE_URL="postgresql+asyncpg://grimoire:ci_integration@${PG_IP}:5432/grimoire_test" # Wait for Postgres. The run: shell is dash (no bash /dev/tcp), so use Python. /opt/venv/bin/python - "$PG_IP" <<'PY' import socket, sys, time diff --git a/Dockerfile b/Dockerfile index 248d0b9d..d53ffedd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,7 +31,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \ # alembic and hypercorn in CMD have to be found there. ENV PATH="/app/.venv/bin:$PATH" -COPY --from=build-frontend /build/dist/ src/scribe/static/ +COPY --from=build-frontend /build/dist/ src/grimoire/static/ COPY alembic.ini . COPY alembic/ alembic/ @@ -57,4 +57,4 @@ ENV APP_CHANNEL=$BUILD_CHANNEL ENV APP_COMMIT=$BUILD_COMMIT EXPOSE 5000 -CMD ["sh", "-c", "alembic upgrade head && hypercorn 'scribe.app:create_app()' --bind 0.0.0.0:5000 --keep-alive 600"] +CMD ["sh", "-c", "alembic upgrade head && hypercorn 'grimoire.app:create_app()' --bind 0.0.0.0:5000 --keep-alive 600"] diff --git a/alembic/env.py b/alembic/env.py index 0ba83fd2..e899d3df 100644 --- a/alembic/env.py +++ b/alembic/env.py @@ -4,9 +4,9 @@ from logging.config import fileConfig from alembic import context from sqlalchemy.ext.asyncio import create_async_engine -from scribe.config import Config -from scribe.models import Base -from scribe.services.db_ready import wait_for_database +from grimoire.config import Config +from grimoire.models import Base +from grimoire.services.db_ready import wait_for_database config = context.config if config.config_file_name is not None: diff --git a/alembic/versions/0122_seal_forge_tokens.py b/alembic/versions/0122_seal_forge_tokens.py index 86c8bacd..b3821a11 100644 --- a/alembic/versions/0122_seal_forge_tokens.py +++ b/alembic/versions/0122_seal_forge_tokens.py @@ -43,7 +43,7 @@ _LABEL_V1 = b"scribe.secrets.v1\x00" def _fernet(): from cryptography.fernet import Fernet - from scribe.config import Config + from grimoire.config import Config digest = hashlib.sha256(_LABEL_V1 + Config.SECRET_KEY.encode()).digest() return Fernet(base64.urlsafe_b64encode(digest)) diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index c821b44e..1d19d84c 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -1,14 +1,14 @@ services: app: - image: git.fabledsword.com/bvandeusen/fabledscribe:latest + image: git.fabledsword.com/bvandeusen/fabledgrimoire:latest environment: - DATABASE_URL: "postgresql+asyncpg://scribe:${DB_PASSWORD}@db:5432/scribe" + DATABASE_URL: "postgresql+asyncpg://${POSTGRES_USER:-grimoire}:${DB_PASSWORD}@db:5432/${POSTGRES_DB:-grimoire}" SECRET_KEY: "${SECRET_KEY}" LOG_LEVEL: "${LOG_LEVEL:-INFO}" TRUST_PROXY_HEADERS: "true" SECURE_COOKIES: "true" networks: - - scribe_backend + - backend db: # Postgres 17 with the vector extension Grimoire needs. @@ -17,15 +17,16 @@ services: volumes: - pgdata:/var/lib/postgresql/data environment: - POSTGRES_USER: scribe + POSTGRES_USER: ${POSTGRES_USER:-grimoire} POSTGRES_PASSWORD: "${DB_PASSWORD}" - POSTGRES_DB: scribe + POSTGRES_DB: ${POSTGRES_DB:-grimoire} networks: - - scribe_backend + - backend volumes: pgdata: + name: ${PGDATA_VOLUME:-grimoire_pgdata} networks: - scribe_backend: + backend: driver: overlay diff --git a/docker-compose.quickstart.yml b/docker-compose.quickstart.yml index 62133c39..90af1f63 100644 --- a/docker-compose.quickstart.yml +++ b/docker-compose.quickstart.yml @@ -5,11 +5,11 @@ services: app: - image: git.fabledsword.com/bvandeusen/fabledscribe:latest + image: git.fabledsword.com/bvandeusen/fabledgrimoire:latest ports: - "5000:5000" environment: - DATABASE_URL: "postgresql+asyncpg://scribe:scribe@db:5432/scribe" + DATABASE_URL: "postgresql+asyncpg://${POSTGRES_USER:-grimoire}:${POSTGRES_PASSWORD:-grimoire}@db:5432/${POSTGRES_DB:-grimoire}" # Set SECRET_KEY in the environment or a .env file beside this one. SECRET_KEY: "${SECRET_KEY:-change-me-in-production}" LOG_LEVEL: "${LOG_LEVEL:-INFO}" @@ -26,9 +26,9 @@ services: volumes: - pgdata:/var/lib/postgresql/data environment: - POSTGRES_USER: scribe - POSTGRES_PASSWORD: scribe - POSTGRES_DB: scribe + POSTGRES_USER: ${POSTGRES_USER:-grimoire} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-grimoire} + POSTGRES_DB: ${POSTGRES_DB:-grimoire} restart: unless-stopped volumes: diff --git a/docker-compose.yml b/docker-compose.yml index 3aed715a..2a420706 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ services: # Or a bind mount, for direct host access to the app's data: # - ./data:/data environment: - DATABASE_URL: "postgresql+asyncpg://${POSTGRES_USER:-scribe}:${POSTGRES_PASSWORD:-scribe}@db:5432/${POSTGRES_DB:-scribe}" + DATABASE_URL: "postgresql+asyncpg://${POSTGRES_USER:-grimoire}:${POSTGRES_PASSWORD:-grimoire}@db:5432/${POSTGRES_DB:-grimoire}" SECRET_KEY: "${SECRET_KEY:-dev-secret-change-me}" # Optional: a SearXNG instance to list as the web-search backend in Integrations. # SEARXNG_URL: "http://searxng:8080" @@ -24,9 +24,9 @@ services: volumes: - pgdata:/var/lib/postgresql/data environment: - POSTGRES_USER: ${POSTGRES_USER:-scribe} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-scribe} - POSTGRES_DB: ${POSTGRES_DB:-scribe} + POSTGRES_USER: ${POSTGRES_USER:-grimoire} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-grimoire} + POSTGRES_DB: ${POSTGRES_DB:-grimoire} volumes: pgdata: diff --git a/docs/api-keys-and-mcp.md b/docs/api-keys-and-mcp.md index 77815ed6..775b3a7e 100644 --- a/docs/api-keys-and-mcp.md +++ b/docs/api-keys-and-mcp.md @@ -35,7 +35,7 @@ Click **Revoke** next to the key in the keys table and confirm. Revoked keys are Grimoire exposes itself as a set of MCP tools that Claude (and other MCP clients) can use to read and write your notes, tasks, projects, rulebooks, and more. The server is **built into the app** — it is mounted as a streamable-HTTP endpoint -at **`/mcp`** on the running Grimoire instance (`src/scribe/mcp/server.py`). There +at **`/mcp`** on the running Grimoire instance (`src/grimoire/mcp/server.py`). There is nothing to install: no wheel, no separate package, no CLI. You connect a client straight to the URL with a Bearer token. @@ -90,7 +90,7 @@ specific project at a dev instance or an admin key. ### Available Tools There are well over a hundred tools and they change with the app, so the -registration in **`src/scribe/mcp/tools/`** is the reference. By family: +registration in **`src/grimoire/mcp/tools/`** is the reference. By family: | Family | Examples | Purpose | |--------|----------|---------| @@ -111,4 +111,4 @@ registration in **`src/scribe/mcp/tools/`** is the reference. By family: Server-level usage guidance — when to reach for each entity, the recall-before-acting reflex, and the rulebook conventions — is delivered to the client automatically via the MCP server's `instructions` block (defined in -`src/scribe/mcp/server.py`). +`src/grimoire/mcp/server.py`). diff --git a/docs/api-reference.md b/docs/api-reference.md index c815b8aa..c953cba0 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -294,7 +294,7 @@ These serve the plugin's hooks. ## Grimoire MCP Claude clients connect to the built-in MCP server at `POST /mcp` (streamable HTTP, -Bearer auth with an `fmcp_` key), served by `src/scribe/mcp/`. It is not a REST +Bearer auth with an `fmcp_` key), served by `src/grimoire/mcp/`. It is not a REST surface — it exposes the same data as typed tools (`create_note`, `create_task`, `start_planning`, `search`, `enter_project`, …) with server-level usage guidance delivered in the MCP `instructions` block. See diff --git a/docs/architecture.md b/docs/architecture.md index 886a5098..735821cb 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -24,10 +24,10 @@ Grimoire is one app container and one PostgreSQL container. There is no language ``` - **The web UI** is a Vue single-page app, built into the image and served by Quart. Every unknown path that isn't under `/api/` falls back to `index.html`; `/api/*` always answers JSON. -- **The REST API** (`src/scribe/routes/`) backs the UI, one blueprint per resource. -- **The MCP server** (`src/scribe/mcp/`) is how Claude reads and writes records. Each module in `mcp/tools/` registers its tools, and the server's instructions and each tool's docstring are the contract an agent reads. Requests authenticate with an API key as a Bearer token. +- **The REST API** (`src/grimoire/routes/`) backs the UI, one blueprint per resource. +- **The MCP server** (`src/grimoire/mcp/`) is how Claude reads and writes records. Each module in `mcp/tools/` registers its tools, and the server's instructions and each tool's docstring are the contract an agent reads. Requests authenticate with an API key as a Bearer token. - **The plugin** (`plugin/`) runs in the user's Claude Code. Its hooks call `/api/plugin/*` to put the right context in front of Claude at the right moment: the project at session start, matching rules and prior art before a prompt or a tool call, the rules mounted on a moment of work, and a check on the reply that ends a turn. Its skills describe the working practices. See [API Keys & MCP](api-keys-and-mcp.md) to install it. -- **Services** (`src/scribe/services/`) hold the logic both doors share. Routes and MCP tools stay thin: parse the request, check access, call a service, return a plain dict. +- **Services** (`src/grimoire/services/`) hold the logic both doors share. Routes and MCP tools stay thin: parse the request, check access, call a service, return a plain dict. ## Data model @@ -80,14 +80,14 @@ Credentials Grimoire stores for outside services (forge tokens, the backup desti ``` ├── alembic/versions/ database migrations -├── src/scribe/ +├── src/grimoire/ │ ├── app.py app factory, blueprints, startup and shutdown │ ├── config.py environment configuration │ ├── models/ SQLAlchemy models │ ├── routes/ REST blueprints │ ├── mcp/ MCP server and its tool modules │ ├── services/ shared logic -│ └── restore.py `python -m scribe.restore` for a fresh instance +│ └── restore.py `python -m grimoire.restore` for a fresh instance ├── frontend/src/ views, components, stores, composables, api client ├── plugin/ Claude Code hooks, skills and commands ├── scripts/ CI checks and the plugin version minter diff --git a/docs/backups.md b/docs/backups.md index 9a4e00d2..df93be32 100644 --- a/docs/backups.md +++ b/docs/backups.md @@ -11,9 +11,12 @@ Set it up under **Settings → Data → Scheduled backups** (admins only). One file per run, named for the moment it was taken in UTC: ``` -scribe-20261015T020000Z.tar +grimoire-20261015T020000Z.tar ``` +Backups written while the app was called Scribe are named `scribe-…tar`. +They are counted with the rest and restore the same way. + It is a plain, **uncompressed** tar: - `manifest.json` comes first. It holds the backup format version, the Grimoire @@ -65,12 +68,12 @@ A path **inside the Grimoire container**, normally a share mounted there: ```yaml services: - scribe: + grimoire: volumes: - - /nfs/backup/scribe:/backups + - /nfs/backup/grimoire:/backups ``` -Grimoire writes each file under a hidden name (`.scribe-….tar.part`) and renames +Grimoire writes each file under a hidden name (`.grimoire-….tar.part`) and renames it once it is complete. A program watching the folder never sees half a backup. @@ -115,7 +118,7 @@ page asks for the secret again. [Fabled Archives](https://git.fabledsword.com/bvandeusen/fabledarchives) keeps service backups as "backup targets". Either destination works with it. -1. On Archives' **Backups** page, make a target for Grimoire, named `scribe` +1. On Archives' **Backups** page, make a target for Grimoire, named `grimoire` for example. 2. Choose how Grimoire's files arrive: - **S3**: turn on the S3 way in for the target and make an **append-only** @@ -124,8 +127,8 @@ keeps service backups as "backup targets". Either destination works with it. - bucket: the target's name; - access key and secret key: the key you just made. - **A folder**: mount the share Archives watches into Grimoire as - `/backups/scribe`, and point the target at that folder. In Grimoire, choose - **A folder** with `/backups/scribe`. + `/backups/grimoire`, and point the target at that folder. In Grimoire, choose + **A folder** with `/backups/grimoire`. 3. Set the target's **Retention** to **Archives**. Archives then keeps the newest backups and thins the rest by day, week and month. Grimoire only adds. 4. Give the target an expected cadence of **daily**, so a missed backup turns @@ -141,7 +144,7 @@ Start Grimoire on an empty database, copy the backup file into the container, and run: ```sh -docker exec -it scribe python -m scribe.restore /backups/scribe-20261015T020000Z.tar +docker exec -it grimoire python -m grimoire.restore /backups/grimoire-20261015T020000Z.tar ``` - The command refuses a database that already has an account. A restore diff --git a/docs/configuration.md b/docs/configuration.md index 56461714..ac7e37ad 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -2,7 +2,7 @@ Grimoire reads its configuration from environment variables. Most settings people change day to day (registration, SMTP, retrieval thresholds, backups, forge connections) live in **Settings** in the web UI instead. -Any variable marked *secret* can also be read from a file: set `_FILE` to the path, for example a Docker secret at `/run/secrets/scribe_key`. +Any variable marked *secret* can also be read from a file: set `_FILE` to the path, for example a Docker secret at `/run/secrets/grimoire_key`. ## Environment variables @@ -10,7 +10,7 @@ Any variable marked *secret* can also be read from a file: set `_FILE` to | Variable | Default | Description | |----------|---------|-------------| -| `DATABASE_URL` *(secret)* | `postgresql+asyncpg://scribe:scribe@localhost:5432/scribe` | PostgreSQL connection string, using the `asyncpg` driver | +| `DATABASE_URL` *(secret)* | `postgresql+asyncpg://grimoire:grimoire@localhost:5432/grimoire` | PostgreSQL connection string, using the `asyncpg` driver | | `SECRET_KEY` *(secret)* | `dev-secret-change-me` | Signs sessions and seals stored credentials. Set it before first use and keep it (see below) | | `BASE_URL` | `http://localhost:5000` | Public URL, used in email links and OIDC redirects | | `SECURE_COOKIES` | `false` | `true` when Grimoire is served over HTTPS | @@ -79,9 +79,11 @@ docker compose up --build [`docker-compose.prod.yml`](../docker-compose.prod.yml) is a stack file: the app and database on a private overlay network, with `SECURE_COOKIES` and `TRUST_PROXY_HEADERS` on. Provide `DB_PASSWORD` and `SECRET_KEY` in the environment: ```bash -DB_PASSWORD=... SECRET_KEY=... docker stack deploy -c docker-compose.prod.yml scribe +DB_PASSWORD=... SECRET_KEY=... docker stack deploy -c docker-compose.prod.yml grimoire ``` +The database user, database and volume default to `grimoire`. An install created under the name Scribe keeps its data by setting `POSTGRES_USER`, `POSTGRES_DB` and `PGDATA_VOLUME` to the names it was created with. + The shipped files leave out healthchecks and restart policies on purpose. The app waits for its database on startup, and the orchestrator's defaults restart it if it ever exits. ### Volumes diff --git a/docs/development.md b/docs/development.md index 1a925a8f..0e02dc81 100644 --- a/docs/development.md +++ b/docs/development.md @@ -65,7 +65,7 @@ Work happens on `dev`. A release merges `dev` into `main` with a plain merge com ### Backend -- Services open their own session: `async with async_session() as session:` (from `scribe.models`). +- Services open their own session: `async with async_session() as session:` (from `grimoire.models`). - Routes and MCP tools stay thin; the logic lives in `services/`, shared by both. - Access checks go through `services/access.py`, never inline ownership checks. - Every wait on something outside the process has a deadline. diff --git a/docs/features.md b/docs/features.md index 1180b8dd..e7599746 100644 --- a/docs/features.md +++ b/docs/features.md @@ -86,7 +86,7 @@ Share a project, note or task with users or groups, as viewer, editor or admin. - **Personal export**: your notes and tasks as a Markdown ZIP (with YAML frontmatter) or JSON. - **Admin backup and restore**, with ids remapped so a backup restores onto another instance. -- **Scheduled backups**: a daily, dated, uncompressed tar to a folder or an S3-compatible bucket, laid out so a deduplicating tool such as restic stores only what changed. `python -m scribe.restore` brings a fresh instance back from one. See [Backups](backups.md). +- **Scheduled backups**: a daily, dated, uncompressed tar to a folder or an S3-compatible bucket, laid out so a deduplicating tool such as restic stores only what changed. `python -m grimoire.restore` brings a fresh instance back from one. See [Backups](backups.md). ## Sign-in diff --git a/frontend/package-lock.json b/frontend/package-lock.json index dc64e610..6e270dc0 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,11 +1,11 @@ { - "name": "scribe-frontend", + "name": "grimoire-frontend", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "scribe-frontend", + "name": "grimoire-frontend", "version": "0.1.0", "dependencies": { "@fullcalendar/core": "^6.1.20", diff --git a/frontend/package.json b/frontend/package.json index 927b7801..74027f36 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,5 +1,5 @@ { - "name": "scribe-frontend", + "name": "grimoire-frontend", "private": true, "version": "0.1.0", "type": "module", diff --git a/frontend/src/api/version.ts b/frontend/src/api/version.ts index 79e89f00..fe5cead8 100644 --- a/frontend/src/api/version.ts +++ b/frontend/src/api/version.ts @@ -2,7 +2,7 @@ import { apiGet } from "./client"; /** * What `/api/version` answers — the client's half of `build_version_payload` - * (`src/scribe/routes/api.py`), which is where the reasoning for the shape is + * (`src/grimoire/routes/api.py`), which is where the reasoning for the shape is * written down. * * EVERY FIELD BUT `version` IS OPTIONAL, and an absent one means "this build diff --git a/frontend/src/components/BackupScheduleSettings.vue b/frontend/src/components/BackupScheduleSettings.vue index f93870c2..4386ebdb 100644 --- a/frontend/src/components/BackupScheduleSettings.vue +++ b/frontend/src/components/BackupScheduleSettings.vue @@ -187,7 +187,7 @@ async function backUpNow() {

- Each run adds one dated file, scribe-<date>.tar, holding every table + Each run adds one dated file, grimoire-<date>.tar, holding every table as plain lines. It is not compressed, so a deduplicating tool such as restic stores only what changed since the day before. Grimoire never deletes old backups — the destination keeps and thins the history. Sharing, API keys and forge connections are not included. @@ -237,7 +237,7 @@ async function backUpNow() {