fix(plugin): session-start hook reads API token from CLAUDE_PLUGIN_OPTION env, not user_config placeholder #64

Merged
bvandeusen merged 1 commits from dev into main 2026-06-10 00:52:02 -04:00
3 changed files with 24 additions and 9 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{
"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.1",
"version": "0.1.2",
"author": { "name": "Bryan Van Deusen" },
"mcpServers": {
"scribe": {
+1 -1
View File
@@ -5,7 +5,7 @@
"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\""
"command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/scribe_session_context.sh\""
}
]
}
+22 -7
View File
@@ -3,10 +3,18 @@
#
# 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)
# the plugin's userConfig, which Claude Code exports to hook subprocesses as
# CLAUDE_PLUGIN_OPTION_<key> env vars:
# CLAUDE_PLUGIN_OPTION_api_endpoint base URL, no trailing slash
# CLAUDE_PLUGIN_OPTION_api_token fmcp_ API key (sensitive)
# CLAUDE_PLUGIN_OPTION_project_id optional numeric project id
#
# IMPORTANT: do NOT pass these via `${user_config.*}` substitution in
# hooks.json — sensitive userConfig values (api_token) are kept in the keychain
# and are never spliced into a hook command line, so the placeholder arrives
# unexpanded. The harness env vars above are the supported channel. SCRIBE_URL
# / SCRIBE_TOKEN / SCRIBE_PROJECT_ID still override, for the settings.json
# dogfooding path where the hook is wired up by hand.
#
# FAIL-OPEN: any missing tool/config, network error, or unreachable instance
# injects nothing and exits 0. A session must never be blocked by Scribe.
@@ -15,9 +23,16 @@ 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:-}
url=${SCRIBE_URL:-${CLAUDE_PLUGIN_OPTION_api_endpoint:-}}
token=${SCRIBE_TOKEN:-${CLAUDE_PLUGIN_OPTION_api_token:-}}
project_id=${SCRIBE_PROJECT_ID:-${CLAUDE_PLUGIN_OPTION_project_id:-}}
# Guard against an unexpanded `${...}` placeholder reaching us as a literal — it
# would otherwise be sent as a garbage Bearer token and 401. Treat as unset.
case "$url" in *'${'*) url="" ;; esac
case "$token" in *'${'*) token="" ;; esac
case "$project_id" in *'${'*) project_id="" ;; esac
[ -n "$url" ] && [ -n "$token" ] || exit 0
q=""