From 66c4fd1b88948a8e938ec752519b29dd7d28f8c8 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 10 Aug 2026 08:33:40 -0400 Subject: [PATCH 1/3] =?UTF-8?q?fix(sync):=20process-skill=20triggers=20inv?= =?UTF-8?q?oke=20by=20name=20only=20=E2=80=94=20resemblance=20offers,=20ne?= =?UTF-8?q?ver=20substitutes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scribe issue #2582: the sync wrote "Use when {title}-type work is requested" into every generated process skill, so a bespoke live prompt that merely resembled a stored Process got the Process's canned procedure — and inherited approvals embedded in its body (the Drift Audit's fan-out opt-in) that the conversation never granted. Observed live: an explicit systems-review request with its own constraints was answered with the Drift Audit clarify menu recommending ~15 parallel auditors. New trigger contract, both variants: follow verbatim only when invoked by name; on mere resemblance the live instructions govern — offer the process, ask before following, and never inherit embedded approvals the operator hasn't granted in this conversation. (The Drift Audit process record itself was also rewritten to a sequential in-context walk — data change, live already, recorded in the same issue.) Co-Authored-By: Claude Fable 5 --- src/scribe/services/plugin_context.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/scribe/services/plugin_context.py b/src/scribe/services/plugin_context.py index 64b08e4..c8a7859 100644 --- a/src/scribe/services/plugin_context.py +++ b/src/scribe/services/plugin_context.py @@ -223,17 +223,23 @@ async def build_process_manifest(user_id: int) -> dict: f'A shared Scribe process "{title}", authored by {owner} — NOT the' f" operator's own." + (f" {preview}" if preview else "") - + f' Use when {title}-type work is requested, or when asked to run' - f' the "{title}" process — but summarise it and get the operator\'s' - f" go-ahead before following it, since it reflects {owner}'s" - f" judgement rather than theirs." + + f' Use only when the operator asks to run the "{title}" process' + f" by name — and even then summarise it and get their go-ahead" + f" first, since it reflects {owner}'s judgement rather than" + f" theirs. If a request merely resembles this process, the live" + f" instructions govern: offer it by name, don't follow it." ) else: description = ( f'Run the operator\'s saved Scribe process "{title}".' + (f" {preview}" if preview else "") - + f' Use when {title}-type work is requested, or when asked to run' - f' the "{title}" process.' + + f' Use when the operator asks to run the "{title}" process by' + f" name. If a request merely RESEMBLES this process, the live" + f" instructions govern — offer the process by name and ask" + f" before following it; never substitute it for explicit" + f" instructions, and never inherit approvals embedded in it" + f" (e.g. a fan-out opt-in) the operator hasn't granted in this" + f" conversation." ) entry = { "id": it["id"], "name": title, "slug": slug, -- 2.54.0 From 9c68faa0bd5ea5188c6b510dfda661ee06e6feec Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 10 Aug 2026 08:39:02 -0400 Subject: [PATCH 2/3] =?UTF-8?q?feat(processes):=20composition=20contract?= =?UTF-8?q?=20=E2=80=94=20the=20process=20is=20the=20skeleton,=20the=20con?= =?UTF-8?q?versation=20supplies=20the=20parameters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends #2582's fix per the operator's direction: a stored Process must incorporate the context it was triggered with, not displace it. No new plumbing needed — the live context is already in the session; what was missing is the stated contract. get_process now carries it: live constraints/scope/focus fold into the procedure and override its defaults where they disagree; a clarify step asks only what the conversation has NOT already answered (confirm interpretations, don't re-ask); stated concerns become lenses the procedure applies, not text it discards. The sync-generated skill stubs state the short form. Co-Authored-By: Claude Fable 5 --- src/scribe/mcp/tools/processes.py | 10 ++++++++++ src/scribe/services/plugin_context.py | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/scribe/mcp/tools/processes.py b/src/scribe/mcp/tools/processes.py index a9b1abb..c69fc5d 100644 --- a/src/scribe/mcp/tools/processes.py +++ b/src/scribe/mcp/tools/processes.py @@ -87,6 +87,16 @@ async def get_process(name_or_id: str) -> dict: fire mechanism. The operator says "run the process"; call this and follow the returned body (including any 'clarify first' steps it contains). + COMPOSITION CONTRACT — a process is the PROCEDURE, not the whole prompt. + The conversation that invoked it supplies the PARAMETERS: fold the + operator's live constraints, scope, and focus areas into the procedure, + and wherever the two disagree, the live instructions override the + process's defaults. A 'clarify first' step asks only what the + conversation has NOT already answered — confirm your interpretation of + what was said rather than re-asking it, and turn stated concerns (a + posture, a hardware budget, a subsystem under suspicion) into lenses the + procedure applies, not text it discards. + Resolution: numeric id → exact (case-insensitive) title → substring. On an ambiguous substring match, the best (most-recent) match is returned with an `other_matches` list so you can disambiguate with the operator. diff --git a/src/scribe/services/plugin_context.py b/src/scribe/services/plugin_context.py index c8a7859..ea68b68 100644 --- a/src/scribe/services/plugin_context.py +++ b/src/scribe/services/plugin_context.py @@ -239,7 +239,11 @@ async def build_process_manifest(user_id: int) -> dict: f" before following it; never substitute it for explicit" f" instructions, and never inherit approvals embedded in it" f" (e.g. a fan-out opt-in) the operator hasn't granted in this" - f" conversation." + f" conversation. When you do run it, the process is the" + f" skeleton and the conversation supplies the parameters:" + f" constraints stated live override its defaults, and clarify" + f" questions the conversation already answers are confirmed," + f" not re-asked." ) entry = { "id": it["id"], "name": title, "slug": slug, -- 2.54.0 From 5cb7cfe70625722b54ef98e4aba5d07c3ca75f79 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 10 Aug 2026 09:40:23 -0400 Subject: [PATCH 3/3] =?UTF-8?q?feat(processes):=20authoring=20contract=20?= =?UTF-8?q?=E2=80=94=20a=20process=20is=20a=20shape,=20never=20a=20script?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Operator's generalization of #2582: the benefit of nearly every stored process is the accumulated SHAPE — steps, taxonomy, quality bar — and a process must not force anything or overwrite the intent of the request that invoked it. create_process now states the authoring side of the composition contract: no embedded approach mandates, no pre-granted approvals, clarify steps seed from the conversation instead of re-asking it. (All three stored processes were also audited: DRY Pass and Rulebook Review were already propose-approve-apply with no forcing language; both gained the seeded-clarify line — data changes, live already.) Co-Authored-By: Claude Fable 5 --- src/scribe/mcp/tools/processes.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/scribe/mcp/tools/processes.py b/src/scribe/mcp/tools/processes.py index c69fc5d..2ad837e 100644 --- a/src/scribe/mcp/tools/processes.py +++ b/src/scribe/mcp/tools/processes.py @@ -49,6 +49,15 @@ async def create_process( ) -> dict: """Create a stored process (a reusable saved prompt). + AUTHOR IT AS A SHAPE, NOT A SCRIPT. A process's value is the accumulated + procedure — the steps, the taxonomy, the quality bar, the failure modes + worth guarding. It must not force anything the invoking conversation + didn't choose: no embedded approach mandates, no pre-granted approvals + (a fan-out opt-in, a permission to act), no assumptions that overwrite + the live request's intent. The conversation that invokes it supplies the + parameters and always wins where they disagree; write clarify steps to + seed from what the operator already said, not to re-ask it. + Args: title: Process name, e.g. "Drift Audit" (required). body: The full prompt to run later (markdown). Required. -- 2.54.0