From 9924f873b977f70f52fe088b1a3cace4269e7077 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Tue, 9 Jun 2026 23:04:09 -0400 Subject: [PATCH] feat(plugin): ship the Scribe Claude Code plugin in-repo (marketplace + plugin) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per operator: the plugin lives in the app repo so it ships and versions in lockstep with the app and the /api/plugin/context contract it targets (same co-location rationale as the former in-repo MCP). A git-cloned marketplace supports relative plugin sources, so the FabledScribe repo IS the marketplace. - .claude-plugin/marketplace.json — source ./plugin - plugin/.claude-plugin/plugin.json — userConfig (base URL, api key, project id) - plugin/.mcp.json — http scribe server, ${user_config.*} substitution - plugin/hooks/ — SessionStart push-channel hook (fail-open) - plugin/skills/using-scribe — bootstrap skill - plugin/README.md — install via the FabledScribe repo marketplace Phase 2 of plan #755. Install/userConfig-substitution test pending. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude-plugin/marketplace.json | 12 +++++++ plugin/.claude-plugin/plugin.json | 25 ++++++++++++++ plugin/README.md | 47 ++++++++++++++++++++++++++ plugin/hooks/hooks.json | 14 ++++++++ plugin/hooks/scribe_session_context.sh | 35 +++++++++++++++++++ plugin/skills/using-scribe/SKILL.md | 43 +++++++++++++++++++++++ 6 files changed, 176 insertions(+) create mode 100644 .claude-plugin/marketplace.json create mode 100644 plugin/.claude-plugin/plugin.json create mode 100644 plugin/README.md create mode 100644 plugin/hooks/hooks.json create mode 100755 plugin/hooks/scribe_session_context.sh create mode 100644 plugin/skills/using-scribe/SKILL.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json new file mode 100644 index 0000000..4dd0be8 --- /dev/null +++ b/.claude-plugin/marketplace.json @@ -0,0 +1,12 @@ +{ + "name": "scribe-plugin", + "owner": { "name": "Bryan Van Deusen" }, + "description": "Scribe ships its own Claude Code plugin from this repo, versioned in lockstep with the app + the /api/plugin/context contract.", + "plugins": [ + { + "name": "scribe", + "source": "./plugin", + "description": "Scribe second brain: MCP tools + session-start push channel + universal process-skills." + } + ] +} diff --git a/plugin/.claude-plugin/plugin.json b/plugin/.claude-plugin/plugin.json new file mode 100644 index 0000000..f5afc61 --- /dev/null +++ b/plugin/.claude-plugin/plugin.json @@ -0,0 +1,25 @@ +{ + "name": "scribe", + "description": "Scribe second brain for Claude Code: MCP tools over your notes/tasks/projects/rules, a session-start push channel that surfaces your always-on rules + active-project context, and a set of universal process-skills (brainstorm, debug, TDD, plan, verify). Replaces superpowers + file-memory with one app-backed plugin.", + "version": "0.1.0", + "author": { "name": "Bryan Van Deusen" }, + "mcpServers": "./.mcp.json", + "userConfig": { + "api_endpoint": { + "type": "string", + "title": "Scribe base URL", + "description": "Base URL of your Scribe instance, no trailing slash (e.g. https://scribe.example.com)" + }, + "api_token": { + "type": "string", + "title": "Scribe API key", + "description": "An fmcp_ API key from Settings → API Keys (read scope is enough for the session-start hook; write scope to use the tools)", + "sensitive": true + }, + "project_id": { + "type": "string", + "title": "Active project id (optional)", + "description": "Numeric Scribe project id to scope the session-start context. Leave blank to inject standing rules only." + } + } +} diff --git a/plugin/README.md b/plugin/README.md new file mode 100644 index 0000000..77d6104 --- /dev/null +++ b/plugin/README.md @@ -0,0 +1,47 @@ +# Scribe plugin for Claude Code + +Turns a self-hosted [Scribe](https://git.fabledsword.com/bvandeusen/FabledScribe) +instance into a first-class Claude Code extension: + +- **MCP tools** over your notes, tasks, projects, milestones, events, typed + entities, and rulebook (the `scribe` server). +- **Session-start push channel** — a `SessionStart` hook injects your always-on + rules + active-project context so Scribe surfaces *without being asked*. +- **Universal process-skills** — brainstorm, systematic-debugging, TDD, + writing-plans, verification, receiving-code-review (replaces superpowers). + +It is designed so you can uninstall `superpowers` and disable auto-memory and +depend on neither. + +## Install + +The plugin ships inside the Scribe app repo, so the marketplace *is* that repo — +you always get the plugin version that matches your Scribe instance. + +``` +/plugin marketplace add https://git.fabledsword.com/bvandeusen/FabledScribe.git +/plugin install scribe@scribe-plugin +``` + +On install you'll be asked for: + +| Setting | What | +|---|---| +| **Scribe base URL** | e.g. `https://scribe.example.com` (no trailing slash) | +| **Scribe API key** | an `fmcp_` key from **Settings → API Keys** (stored in your OS keychain) | +| **Active project id** | optional — numeric project id to scope the session-start context | + +## What gets wired + +- `.mcp.json` → the `scribe` MCP server at `/mcp` (Bearer auth). +- `hooks/hooks.json` → SessionStart hook (`hooks/scribe_session_context.sh`), + **fail-open**: if Scribe is unreachable it injects nothing and never blocks + the session. +- `skills/` → the universal process-skills, surfaced by description match. + +## Notes + +- Set a `version` bump in `.claude-plugin/plugin.json` per release so clients + pick up changes. +- The session-start hook needs only a **read**-scoped key; the MCP tools need + **write** scope to create/update. diff --git a/plugin/hooks/hooks.json b/plugin/hooks/hooks.json new file mode 100644 index 0000000..8e4a6d7 --- /dev/null +++ b/plugin/hooks/hooks.json @@ -0,0 +1,14 @@ +{ + "hooks": { + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "SCRIBE_URL=\"${user_config.api_endpoint}\" SCRIBE_TOKEN=\"${user_config.api_token}\" SCRIBE_PROJECT_ID=\"${user_config.project_id}\" bash \"${CLAUDE_PLUGIN_ROOT}/hooks/scribe_session_context.sh\"" + } + ] + } + ] + } +} diff --git a/plugin/hooks/scribe_session_context.sh b/plugin/hooks/scribe_session_context.sh new file mode 100755 index 0000000..ca7b2c5 --- /dev/null +++ b/plugin/hooks/scribe_session_context.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# Scribe plugin — SessionStart push channel. +# +# Curls the operator's Scribe instance for always-on rules + active-project +# context and emits it as SessionStart `additionalContext`. Config comes from +# plugin userConfig, passed in as env by hooks/hooks.json: +# SCRIBE_URL base URL, no trailing slash (user_config.api_endpoint) +# SCRIBE_TOKEN fmcp_ API key (user_config.api_token) +# SCRIBE_PROJECT_ID optional numeric project id (user_config.project_id) +# +# FAIL-OPEN: any missing tool/config, network error, or unreachable instance +# injects nothing and exits 0. A session must never be blocked by Scribe. +set -uo pipefail + +command -v jq >/dev/null 2>&1 || exit 0 +command -v curl >/dev/null 2>&1 || exit 0 + +url=${SCRIBE_URL:-} +token=${SCRIBE_TOKEN:-} +project_id=${SCRIBE_PROJECT_ID:-} +[ -n "$url" ] && [ -n "$token" ] || exit 0 + +q="" +[ -n "$project_id" ] && q="?project_id=${project_id}" + +body=$(curl -fsS --max-time 8 \ + -H "Authorization: Bearer ${token}" \ + "${url%/}/api/plugin/context${q}" 2>/dev/null) || exit 0 + +text=$(printf '%s' "$body" | jq -r '.context // empty' 2>/dev/null) || exit 0 +[ -n "$text" ] || exit 0 + +jq -n --arg c "$text" \ + '{hookSpecificOutput: {hookEventName: "SessionStart", additionalContext: $c}}' +exit 0 diff --git a/plugin/skills/using-scribe/SKILL.md b/plugin/skills/using-scribe/SKILL.md new file mode 100644 index 0000000..a2a6bbe --- /dev/null +++ b/plugin/skills/using-scribe/SKILL.md @@ -0,0 +1,43 @@ +--- +name: using-scribe +description: Use at the start of any session and before answering questions about the operator's work or starting a task — establishes the Scribe-first reflex (recall before acting, load standing rules, update over duplicate, plan in Scribe not in files). +--- + +# Using Scribe + +Scribe is the operator's self-hosted second brain (notes, tasks, projects, +milestones, events, typed entities) and rulebook, reachable through the bundled +`scribe` MCP server. Its value is mostly in what it **already holds** — so make +reading it a reflex, not something you wait to be asked for. + +## The reflex + +1. **Recall before acting.** Before answering a question about the operator's + work, or starting a task, `search` Scribe (and `list_tasks` / `list_notes`) + for prior art — an existing ticket, decision, or dev-log — instead of + re-deriving it or opening a duplicate. When a project is in scope, pass its + `project_id` so results stay scoped. + +2. **Standing rules are binding.** The SessionStart context lists the operator's + always-on rule titles. Treat them as binding. Pull full text with + `list_always_on_rules()` or `get_rule(id)` when a rule is about to bite. + When a project is in scope, `enter_project(id)` also returns its applicable + rules. + +3. **Update over duplicate.** When recording, prefer updating an existing + note/rule/task over creating a new one. Search first; revise what's there. + +4. **Plans live in Scribe.** For non-trivial work call `start_planning(project_id, + title)` FIRST — the plan body + step checklist live in the `kind=plan` task, + progress goes in work-logs (`add_task_log`). Do not write plans/specs to local + `.md` files. + +5. **Keep state honest.** Set a task `in_progress` when you start it, `done` the + moment it's complete; log progress as you go. + +## Other Scribe process-skills + +This plugin also ships focused process-skills — brainstorming, systematic +debugging, test-driven development, writing-plans, verification, receiving code +review. Reach for the matching one when its situation arises, the same way you +reach for this skill.