feat(plugin): ship the Scribe Claude Code plugin in-repo (marketplace + plugin)
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) <noreply@anthropic.com>
This commit is contained in:
@@ -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."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 `<base URL>/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.
|
||||||
@@ -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\""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+35
@@ -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
|
||||||
@@ -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.
|
||||||
Reference in New Issue
Block a user