`plugin/` is not built into the image; installs fetch it from this repo via
.claude-plugin/marketplace.json, so a push IS the release. It was absent
from the workflow's `paths:` filter entirely, meaning plugin changes ran no
CI at all. Two separate defects reached a live install through that gap:
#2198 — all four hook scripts inert (lowercase userConfig env vars,
line-oriented `jq -rR`, line-oriented `cut -c`)
#2209 — the fix for #2198 couldn't reach an install because the manifest
version wasn't bumped, so the installer never refreshed its cache
Adds `plugin/**` + `.claude-plugin/**` to `paths:` and a `plugin` job
running scripts/check_plugin.py:
1. `bash -n` on every hook.
2. The three known-bad patterns from #2198. Verified by replay against
c569cdd^ — all three are caught. Narrow by design; see below.
3. Shipped plugin content differs from origin/main => the manifest version
must differ too. Stated against the base branch, not per-commit, so a
batch needs one bump rather than one per commit. Replayed against
c569cdd: correctly fails.
The checker found a real outstanding bug on its first run: the `cut -c1-2000`
prompt cap in scribe_autoinject.sh was still line-oriented. Only the
prior-art hook's copy got fixed in c569cdd. Now `head -c`. It then failed
on this very commit for a missing version bump, which is the third time
that rule has mattered and the first time something other than memory
enforced it. Manifest bumped to 0.1.20.
WHAT THIS DOESN'T COVER, and why. shellcheck is the right tool for check 2
and is NOT in ci-python; nor is jq, which every hook requires and silently
bails without — so a "runs and stays silent" smoke test would pass
vacuously today and prove nothing. Both need those two packages added to
the CI image in the CI-runner repo, which is a separate change to a
separate repo (rule #5: the toolchain comes from the image, not from
apt-get at job start). Verified against CI-runner's Dockerfile and
scripts/install-common.sh rather than assumed (rule #37).
`plugin` is not in the build job's `needs`: the plugin doesn't ship in the
image, and blocking the build wouldn't un-publish a bad hook — the push
already did. A failed job still reddens the run.
Closes#2204
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UaYUaouG9jjhATyuxCKrQs
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) <noreply@anthropic.com>
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>
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>
Was failing with ModuleNotFoundError for httpx when run via system
python — httpx is a project dep but isn't on the system interpreter's
path. Adding PEP 723 script metadata + uv-run shebang means the script
auto-resolves its deps in an ephemeral venv on every invocation, no
project-venv setup required.
Run with `uv run scripts/bench_ollama.py …` or directly via the shebang
`./scripts/bench_ollama.py …`. `python scripts/bench_ollama.py …` still
works only when httpx happens to be on the active interpreter.
Docstring updated to reflect the running options.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The curator scenario hardcoded think=true, which is qwen3-family-specific.
Non-qwen3 models silently ignore the field, so cross-family curator
comparisons were apples-to-oranges (qwen thinks, others don't).
New --think flag:
- auto (default): scenario-driven — chat=off, curator=on. Matches the
prior behaviour and the most common case.
- off: force disabled across all runs. Use for fair cross-family
comparison; aligns behaviour explicitly even though non-qwen models
would ignore think anyway.
- on: force enabled across all runs. Use to measure what think
contributes on the same model (paired runs: --think off then on).
Output markdown table now records the think mode used, so saved results
are self-documenting when you diff cross-server or cross-config.
Docstring + usage examples updated to reflect the qwen3 candidate set
the bench was originally tuned for.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Standalone tool to measure Ollama model performance under the two
workload shapes the chat+curator architecture would impose:
- chat scenario: short user message, short reply, no thinking. Mirrors
the no-tools chat companion's expected load.
- curator scenario: ~700-token journal transcript with an extraction
prompt, thinking enabled. Mirrors the curator's expected load.
Defaults to CPU-only inference (num_gpu=0). Streams responses; reports
TTFT, total wall time, tokens/sec (from Ollama's eval_count/eval_duration
so it excludes client-side stream overhead), and prompt token count.
First request per (model, num_gpu) is a warm-up to load the model into
memory; not counted in the measured runs.
Designed for cross-server comparison: --server points at any Ollama
instance, --out writes a markdown table. Comparing the two CPU servers
becomes a matter of running the same command on each and diffing the
output.
Lives outside the chat/curator architecture commitment — measurement
tool only. Tells us "is qwen2.5:32b on CPU fast enough for a 10-20 min
curator cadence?" without writing any of the architecture code yet.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Derive REPO_ROOT from the script's own location instead of hardcoding
the absolute project path, so the hook keeps working if the project
directory is renamed or moved.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- scripts/bump_fable_mcp_version.sh: increments patch in pyproject.toml and stages it
- scripts/pre_commit_fable_mcp.sh: PreToolUse Bash hook — fires before git commits,
bumps version if fable-mcp files (other than pyproject.toml itself) are staged
- .claude/settings.json: registers the PreToolUse hook
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>