Commit Graph
59 Commits
Author SHA1 Message Date
bvandeusenandClaude Opus 4.8 85e0501705 feat(issues): S2 MCP tools — system CRUD + issue/system wiring
CI & Build / Python lint (push) Successful in 2s
CI & Build / TypeScript typecheck (push) Successful in 34s
CI & Build / Python tests (push) Successful in 50s
CI & Build / Build & push image (push) Successful in 1m3s
Second slice of Issues + Systems (spec #825).

New mcp/tools/systems.py: create_system, list_systems, get_system (records
split into issues/tasks/notes), update_system (incl. archive via status),
list_system_records (kind/open_only filters), delete_system. Registered in
register_all; read tools (get_system, list_systems, list_system_records) added
to the read-only-key allowlist (write tools default-deny).

create_task/update_task: kind now accepts 'issue'; new system_ids (set-semantics
associations) and arose_from_id (provenance, 0=unchanged/-1=clear) args.
create_note/update_note: new system_ids arg (notes associate with systems too).
services/notes.create_note: arose_from_id passthrough (update_note already
handles it via setattr).

Tests: MCP system tools + create_task issue-wiring (kind/provenance/systems),
service layer mocked.

Refs plan 825 (S2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 23:07:37 -04:00
bvandeusenandClaude Opus 4.8 b91c447b0b feat(issues): S1 schema — issue task_kind, System entity, associations
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Python tests (push) Successful in 49s
CI & Build / Build & push image (push) Successful in 1m5s
First slice of the Issues + Systems feature (spec #825, plan #819 T2).

Schema (migration 0065):
- task_kind CHECK expands work|plan -> work|plan|issue (same-change, rule 36)
- notes.arose_from_id: optional self-FK for issue->originating-task provenance
  (distinct from parent_id sub-task hierarchy)
- systems: per-project, self-describing (name + description) subsystem/area
- record_systems: M2M join linking any note/task/issue to systems (mutable)

Models: System + RecordSystem; note.py gains arose_from_id (+ index, to_dict).
Service services/systems.py: CRUD, archive, soft-delete, set/list associations,
records-for-system, open-issue count — all gated via services/access.py project
permissions (rule 78, no bare-owner filters). Unit tests lock the ACL gating;
the migration is exercised by CI's integration lane (alembic upgrade head).

is_task stays a derived property (status is not None) — unchanged. T1 (typing-
axis rationalization) intentionally NOT bundled; this only adds the enum value.

Refs plan 825 (S1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 22:53:51 -04:00
bvandeusenandClaude Opus 4.8 da511fcc9f feat(ui): declutter dashboard done-recently + MCP-access, add per-project stats
CI & Build / Python lint (push) Successful in 2s
CI & Build / TypeScript typecheck (push) Successful in 31s
CI & Build / Python tests (push) Successful in 49s
CI & Build / Build & push image (push) Successful in 58s
Dashboard:
- 'Done recently' chip-cloud -> compact uniform list (Active-now row style),
  showing 5 with inline expand to the rest (backend already returns up to 8).
- New 'Projects' rail card: each active project with 'N open · M done'.
  Backend already computed done_count (dashboard.py) — now surfaced in the
  /api/dashboard payload per active project.

MCP Access (Connect Claude / Claude Code):
- Progressive disclosure: lead with the pre-filled plugin-install snippet;
  fold server name, scope, marketplace URL, and the MCP-only path into a
  single 'Customize' expander. Desktop tab keeps its own server-name field.
- Marketplace URL now defaults to this instance's own repo via
  config.PLUGIN_MARKETPLACE_URL (env-overridable); /api/plugin/marketplace-url
  falls back to it, so the field + install snippet are pre-filled out of the
  box instead of showing a generic placeholder.

Refs #761

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 11:04:23 -04:00
bvandeusenandClaude Opus 4.8 8fe571e175 feat(plugin): resolve session project from git remote, not a pinned project_id
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Successful in 51s
CI & Build / Build & push image (push) Successful in 1m0s
The SessionStart hook asked for a project_id via plugin userConfig, which pins
one install to a single project — wrong for an operator working across many
repos/projects. Resolve the active project server-side from the working repo's
git remote instead (a stable identifier, not a dir-name guess).

- repo_bindings table (migration 0064) + RepoBinding model: (user, repo_key) ->
  project, FKs CASCADE.
- services/repo_bindings: normalize_repo_key collapses ssh/https/scp/creds/port/
  .git to host/owner/repo; resolve/set/list/delete.
- GET /api/plugin/context takes ?repo=<remote>; unbound repo -> a "bind this
  repo" hint with a ready bind_repo() call. project_id kept as manual override.
- MCP tools: bind_repo / list_repo_bindings / unbind_repo.
- Hook sends ?repo=$(git remote get-url origin) URL-encoded; all project_id
  handling removed. plugin.json drops the project_id userConfig (0.1.2 -> 0.1.3).
- Tests: normalize equivalence classes + unbound-hint rendering.

Refs task 755 (Scribe-as-plugin push channel).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 01:33:58 -04:00
bvandeusenandClaude Opus 4.8 1d82e81527 feat(plugin): admin-configurable marketplace URL as the install default
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Successful in 46s
CI & Build / Build & push image (push) Successful in 59s
The Settings install command had a <your-scribe-repo> placeholder — not
copyable. Add an instance-global 'plugin_marketplace_url' setting (admin sets
it to the app's own repo) that every user's MCP Access reads, so the
/plugin marketplace add command is copyable out of the box. Keeps it universal
(each deployment configures its own repo) rather than hardcoding one.

- services/settings.get_admin_setting(key): admin-scoped global read.
- routes/plugin: GET /api/plugin/marketplace-url (any user) + PUT (admin).
- SettingsView: Admin → 'Plugin marketplace' field to set it; MCP Access
  marketplace field falls back to the configured value.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 00:17:05 -04:00
bvandeusenandClaude Opus 4.8 d6c8470ab2 feat(backup): v3 backup covers rulebooks, rules, events + join tables
The v2 backup silently dropped the entire rulebook system (rulebooks, topics,
rules), the project subscription/suppression join tables, and events — so a
'full' backup wasn't. v3 adds all of them with FK re-mapping on restore, and a
_not_included field that names the still-deferred tables (ACL groups/shares,
api_keys, embeddings, transient/operational) so the gap is explicit, not silent.

restore_full_backup routes v2 and v3 through one path; v3-only sections are
guarded by data.get so a v2 payload still restores cleanly.

Tests: version/coverage constants, pure join-table row helpers, and the export
contract via a mocked session (CI has no DB; full round-trip is a manual check).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 23:52:14 -04:00
bvandeusenandClaude Opus 4.8 3ab16fcbdb feat(plugin): add /api/plugin/context push-channel endpoint + dogfood hook
CI & Build / Python lint (push) Successful in 2s
CI & Build / TypeScript typecheck (push) Successful in 35s
CI & Build / Python tests (push) Successful in 49s
CI & Build / Build & push image (push) Successful in 1m6s
Phase 1 of plan #755 (Scribe-as-plugin). Gives Scribe its own session-start
push channel so always-on rules + active-project context surface without being
asked — the gap behind 'I have to prompt for everything'.

- services/plugin_context.build_session_context: renders always-on rule titles
  grouped by topic (under the 10k additionalContext cap; full text stays one
  list_always_on_rules/get_rule call away) + optional project goal/open-task
  count + a recall/update-over-create reflex line. Capped at 9000 chars.
- routes/plugin GET /api/plugin/context (login_required already accepts Bearer
  fmcp_ keys; read scope suffices).
- tests: titles-not-statements, project scoping, length cap (pure mocks).
- scripts/scribe_session_context.sh: dogfood SessionStart hook, fail-open,
  reads url+token from .mcp.json. Superseded in Phase 2 by the plugin-bundled
  hook using userConfig.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 22:43:08 -04:00
bvandeusenandClaude Opus 4.8 70ab3f38c6 chore: remove pre-pivot dead code + finish Scribe rebrand (#599 t1-3)
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 35s
CI & Build / Python tests (push) Successful in 51s
CI & Build / Build & push image (push) Successful in 1m1s
- Header wordmark Fabled -> Scribe; fable:calendar-changed event ->
  scribe:calendar-changed; SettingsView CSS comment.
- Drop dead Project.auto_summary + summary_updated_at columns (migration
  0063) -- the Ollama-era summarizer is gone; model + 2 frontend types +
  projects test updated.
- Remove pivot vestiges: diagnostics _curator_busy()/curator_busy
  heartbeat field, tz BRIEFING_DAY_START_HOUR/user_briefing_date dead
  aliases, the ignored 'model' param on get_embedding (+ its test).

ruff src/ clean; CI is the gate. Part of scribe plan #599.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 16:16:44 -04:00
bvandeusenandClaude Opus 4.8 b255a0f90e refactor: rename package fabledassistant -> scribe (code-only)
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 35s
CI & Build / Python tests (push) Successful in 54s
CI & Build / Build & push image (push) Successful in 1m14s
Renames src/fabledassistant -> src/scribe and all imports, plus the
default DB name and DB user/password (fabled -> scribe) in config +
compose. 952 refs / 154 files. Reverses the old 'internal name stays
fabledassistant' convention.

Code-only: live databases are still physically named 'fabledassistant'.
Deployed environments must set POSTGRES_DB / POSTGRES_USER (or rename the
DB) since the defaults now resolve to 'scribe'. Repo (FabledScribe), git
host (fabledsword), MCP (fabled-git) and the image name (fabledscribe)
are intentionally unchanged.

ruff check src/ clean locally; CI (typecheck + pytest) is the gate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 15:48:35 -04:00