From 30826d250cf12d55ffd33b48d39c82bb01a2d09b Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 10 Jun 2026 01:49:12 -0400 Subject: [PATCH 1/2] chore: remove pre-plugin scribe_session_context.sh dogfood hook Superseded by the plugin's own SessionStart hook (plugin/hooks/). This root scripts/ copy read the now-deleted project .mcp.json (dead scribe-dev / devassistant host), so it could never fire. Single Scribe environment now, reached only via the Scribe plugin MCP. Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/scribe_session_context.sh | 38 ------------------------------- 1 file changed, 38 deletions(-) delete mode 100755 scripts/scribe_session_context.sh diff --git a/scripts/scribe_session_context.sh b/scripts/scribe_session_context.sh deleted file mode 100755 index ecde6c6..0000000 --- a/scripts/scribe_session_context.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash -# Scribe SessionStart hook (dogfood / pre-plugin). -# -# Curls the running Scribe dev instance for the operator's always-on rules + -# active-project context and emits it as SessionStart `additionalContext` — the -# push channel that lets Scribe surface reflexively (plan #755, Phase 1). -# -# FAIL-OPEN by design: any missing tool, missing config, network error, or -# unreachable instance results in injecting nothing and exiting 0. A session -# must NEVER be blocked because Scribe is down. Reads URL+token from the -# project's .mcp.json so no secret lives in this tracked script. -# -# Superseded in Phase 2 by the same hook bundled in the Scribe plugin, where -# URL+token come from plugin userConfig instead of .mcp.json. -set -uo pipefail - -MCP_JSON="${CLAUDE_PROJECT_DIR:-.}/.mcp.json" -command -v jq >/dev/null 2>&1 || exit 0 -command -v curl >/dev/null 2>&1 || exit 0 -[ -f "$MCP_JSON" ] || exit 0 - -# scribe-dev is the locally-wired instance (prod id 2 / dev id 3 per binding). -url=$(jq -r '.mcpServers["scribe-dev"].url // empty' "$MCP_JSON" 2>/dev/null) || exit 0 -auth=$(jq -r '.mcpServers["scribe-dev"].headers.Authorization // empty' "$MCP_JSON" 2>/dev/null) || exit 0 -token=${auth#Bearer } -[ -n "$url" ] && [ -n "$token" ] || exit 0 - -base=${url%/mcp} -body=$(curl -fsS --max-time 8 \ - -H "Authorization: Bearer ${token}" \ - "${base}/api/plugin/context?project_id=3" 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 From 1983e8f4b14874e368c43659fe6e9b088d9573bf Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 10 Jun 2026 02:19:13 -0400 Subject: [PATCH 2/2] feat(plugin): make using-scribe skill actively pull standing rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SessionStart push channel cannot reliably deliver a sensitive API token to the hook subprocess (upstream Claude Code bug anthropics/ claude-code#62442 — sensitive plugin userConfig is not persisted and is absent on a normal session). Stop depending on that push for standing rules: make the using-scribe bootstrap skill own the load instead. - description: name the FIRST ACTION (list_always_on_rules + enter_project when a repo/project is in scope) so it auto-surfaces at session start - add a 'Do this first' block instructing an active pull; demote the SessionStart hook to a bonus, not a precondition (it fail-opens and may be absent) - reflex step 2: rules come from list_always_on_rules(), not from an assumed SessionStart injection The hook + hooks.json are left in place: they fail-open and resume adding value automatically if #62442 is fixed or the token is made non-sensitive. Refs #755 (Phase 1: push channel descoped to optional; pull is load-bearing) Co-Authored-By: Claude Opus 4.8 (1M context) --- plugin/skills/using-scribe/SKILL.md | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/plugin/skills/using-scribe/SKILL.md b/plugin/skills/using-scribe/SKILL.md index a2a6bbe..cd9aff8 100644 --- a/plugin/skills/using-scribe/SKILL.md +++ b/plugin/skills/using-scribe/SKILL.md @@ -1,6 +1,6 @@ --- 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). +description: Use at the START of every session, and before answering anything about the operator's work or starting any task — establishes the Scribe-first reflex. FIRST ACTION of a session: call list_always_on_rules() (and enter_project when a repo/project is in scope) to load the operator's binding rules. Then recall before acting, update over duplicate, plan in Scribe not in files. --- # Using Scribe @@ -10,6 +10,20 @@ 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. +## Do this first (every session) + +**Pull the standing rules yourself — do not wait for them to be handed to you.** +At the start of a session, before substantive work, call +`list_always_on_rules()` to load the operator's always-on rules. If the working +repo maps to a Scribe project (you're in a known repo, or `list_repo_bindings` +shows a binding), call `enter_project(id)` instead/as-well — it returns the +project plus its applicable rules, open tasks, and recent notes in one shot. + +Do this actively. A SessionStart hook *may* also inject a rule index, but treat +that as a bonus, not a precondition: it can be absent (e.g. when the instance is +unreachable, or the token didn't reach the hook), so the reliable path is this +explicit pull. Rules loaded this way are **binding** for the session. + ## The reflex 1. **Recall before acting.** Before answering a question about the operator's @@ -18,11 +32,10 @@ reading it a reflex, not something you wait to be asked for. 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. +2. **Standing rules are binding.** Load them via `list_always_on_rules()` at + session start (see "Do this first"); treat every one as binding. Pull a + rule's full statement with `get_rule(id)` when it's 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.