Releases: chrisp28103/sn-toolkit
v1.35.1 -- fix overstated Prerequisites claim in both READMEs
Corrects an inaccurate Prerequisites claim in both READMEs. The "without sn-scriptsync + SN Utils, every slash command times out" line overstated the dependency.
Fixed
README.md(repo-root marketplace front page) andsn-toolkit/README.md(plugin "Prerequisites") -- the "times out without the stack" warning is now scoped to commands that touch a live ServiceNow instance (start/pull/create/update/widget/diagnose/ ...), and the instance-free commands that work without the bridge (worddoc,spec,workshop,workbook,refine-prompt,docs) are named explicitly. The stack stays not optional for the core SN dev loop.
Docs-only, zero token cost.
v1.35.0 -- rebalance edit-path guidance (update_record/_batch the default editor, file-sync opt-in)
Rebalances the artifact-editing guidance so the direct Agent API (update_record / update_record_batch) is the first-class default for editing existing artifacts -- including script fields (Script Include / Business Rule / Client Script bodies, widget code) -- and the sn-scriptsync local file-sync workflow is consistently framed as an opt-in path for those who specifically want a version-controlled local copy, not the canonical edit path.
The premise behind the old bias -- that update_record is unreliable for large script payloads -- was tested live on dev221527 and refuted: update_record persists script fields cleanly from 5 KB to 8 MB with zero truncation. The only real caveat is bumping the wrapper's default 15s timeout (-TimeoutSeconds) on multi-MB payloads.
The audit was an adversarial fan-out (one opus reader + one sonnet verifier per file) across all 33 docs / rules / hooks / agents / READMEs / tooltips; 28 came back clean, including the create scope flow, the anti-background-script tool-guard, and sync-push.md.
Changed
commands/update.md-- script fields removed from "Do NOT use for" and added to "DO use it for"; synced-file path named as opt-in version control; accurate timeout caveat added (no truncation limit).commands/widget.md-- "Edit Existing Widget" split into Path A (directupdate_record_batch, default) and Path B (file/preview loop, opt-in); drops the "for fields without local files" no-file-fallback framing.skills/learn/SKILL.md-- golden path no longer treatssync-pushas the universal landing step (updateverifies itself); worked-example pairing leads withpull -> update.CLAUDE.md.template--update_record/update_record_batchrows and edit guidance reframed as the default for editing existing artifacts incl. script fields.
Docs-only, no behavior or code changes, no new commands, zero always-on token cost. The anti-background-script clause and create-scope guidance are untouched.
v1.34.0 -- create_artifact scoped-create fix (ensure_scope)
Fixes the real cause of create_artifact landing scoped records in global, and retires the switch_context-based scope model that v1.33.0/v1.33.1 shipped on a misdiagnosis.
Reading the sn-scriptsync source (4.5.0 -- the version on both the dev PDI and the affected engagement) settled it: a new record's sys_scope is set by the ?sysparm_transaction_scope=<sys_id> URL parameter, which the extension resolves from the scope parameter's name to a sys_id only via the instance's scopes.json (the file create_application writes). For an OOB/store scope like sn_customerservice -- or any scope not created locally via create_application -- there is no mapping, so the raw name is sent, ServiceNow can't resolve a name as a sys_id, and the record falls back to global. Reproduced on a clean single-tab dev PDI against the identical sn_customerservice sys_id, disproving both the multi-tab/tab-targeting theory and the v1.33.x "switch_context moves the scope" model.
Added
bin/sn-agent-api.ps1-- newensure_scopesynthetic command. Resolves a scope's sys_id and merges{ name: sys_id }into the extension'sscopes.json(UTF-8, no BOM, at the realresolveInstanceFolder<workspace root>/<instance>/, not-InstanceDir) so a subsequentcreate_artifactwithscope=<name>lands correctly and keeps the local_map.jsonfolder named by scope. Returns{scope, sys_id, mapped, alreadyPresent};globalis a no-op.
Fixed
create_artifactlanded scoped records inglobalfor any scope absent fromscopes.json(every OOB/store scope; cause of three failed scoped-create sessions).commands/create.mdStep 5 now runsensure_scopefirst; Step 7'ssys_scope.scoperead-back stays the authoritative gate.
Changed
- Retired the superseded
switch_context-moves-the-create-scope model acrosscreate.md,switch.md,rules/conventions.md,CLAUDE.md.templateRule 8,commands/claude-md-audit.md, and the wrapper.NOTES. The v1.33.0 anti-improvise guardrails are unchanged.
v1.33.1 -- scoped-create docs corrected after live re-verification
Corrects the scoped-create supporting docs after a live re-verification on dev221527, and keeps the v1.33.0 mechanism intact.
Bottom line: the v1.33.0 picker mechanism is CORRECT (re-confirmed by 9 controlled create_artifact runs, including the exact sn_customerservice/CSM scope). A record's sys_scope follows the helper-tab session's current application, set ONLY by the switch_context Agent API command. The scope param, a sys_scope field in the payload, and the bare apps.current_app preference are all ignored. The earlier "refutation" was a flawed test: a manually-set picker writes the preference but does NOT move the helper-tab session create_artifact runs in (replicated exactly).
Fixed
rules/conventions.md-- "thecreate_artifactcommand setssys_scope... from that parameter" was FALSE and contradictedcreate.md. Rewritten to the verified picker-session model (scope param / sys_scope payload field /apps.current_apppref all named as non-drivers).commands/switch.md-- "get_instance_infoshows the active picker state" was FALSE; it returns only{instanceName, hasSettings, connected}. Replaced with the read-backsys_scope.scopeverification.
Changed
commands/create.md-- added the manual-picker-vs-switch_contextnuance, the sys_scope-field-ignored fact, and theresult.scopecheap-check; dropped the over-strong "reload required" claim.commands/switch.md+bin/sn-agent-api.ps1-- softened the reload-required framing (app scope applies without a reload; reload still needed for domain + the visible tab).
Docs-only plus two .NOTES comment lines. The v1.33.0 safety hardening is unchanged. Findings adversarially reviewed (root-cause skeptic + doc-claim auditor + diff reviewer).
v1.33.0 -- guard against improvise-instead-of-fail-loud SN mutations
Hardens the toolkit against a "session improvises a dangerous mutation instead of failing loud" failure family, surfaced by two real incidents and resolved through a two-iteration PFSAI loop plus a dedicated five-lens code review. In one engagement a session created a Business Rule by raw new GlideRecord('sys_script').insert() inside run_background_script after concluding "create_artifact can't target sn_customerservice" -- a partial hallucination (it can; the record's scope follows the helper-tab live Concourse-Picker, not the scope param). In another, a session improvised raw sys_dictionary record inserts to fake a column add after add_column came back Unknown command on a stripped extension build, then retried into a half-applied schema. The fix is defense-in-depth, validated with a 39-payload empirical battery against the live hook and independently reviewed across correctness, false-positive, false-negative, regression, and consistency lenses before shipping.
Added
hooks/tool-guard.ps1PreToolUse Guard 3 (Bash + PowerShell, fail-open). 3a hard-blocks arun_background_scriptthat opensnew GlideRecord('<artifact/metadata table>')AND calls a write method, across 21 code/definition tables; 3b hard-blockscreate_artifactonsys_dictionary(columns go throughadd_column). Data/config tables and reads are not tripped;update_recordon metadata stays permitted (sanctioned edit path).hooks/hooks.jsonaddsPowerShellto the PreToolUse matcher -- the invocation path the incident actually used.CLAUDE.md.templateRules 7 + 8 -- artifacts via/sn-toolkit:create+/sn-toolkit:update; on a failed/unavailable command, STOP rather than improvise, don't blind-retry a half-applied write, verify sent != committed.rules/sn-error-codes.md"Judgment guardrails" -- the STOP / no-retry / verify-commit discipline, withE_DISABLEDandE_TIMEOUTcarve-outs intact.commands/claude-md-audit.mdcapability-assertion + false-capability lenses;commands/start.mdStep 4b capability spot-check (catches a stripped build at session start).
Changed
commands/create.md-- scope preflight (switch_contextbeforecreate_artifact) + unconditional scope-verify (sys_scope.scope, STOP on agloballanding) + the misleading "always include scope" guidance rewritten; trigger now fires on agent-initiated build steps.commands/update.mdtrigger broadened;CLAUDE.md.templateEssential Commands table reframed so the slash commands are the first-glance path.
Fixed
bin/bootstrap-project.ps1--sn-platform-first.mdadded to the rule copy-list (shipped v1.32.0, never wired into bootstrap).
v1.32.0 -- concept-audit ranks 1/2/4: platform-first rule + update.md blast-radius line + Mermaid-in-PDF for /spec
Builds the three items picked from the 2026-06-15 concept-audit backlog (a PFSAI loop over four external concepts: Mermaid diagramming, Scribe auto-docs, Karpathy coding guidelines, Ponytail minimalism). The Mermaid render path was spike-validated, then re-rendered end-to-end on a real machine and screenshot-verified.
Added
rules/sn-platform-first.md-- a path-scoped rule (**/*.js,**/*.html,**/*.scssonly) encoding the OOTB-before-custom decision hierarchy: does it need to exist -> does ServiceNow do it natively -> does an existing artifact cover it -> can it be config/one line -> only then custom script. Establishes a greppable// PLATFORM-FIRST: <reason>justification convention. Narrower thanconventions.md; noagentrules/mirror; zero always-on token cost.- Native Mermaid diagrams in
/sn-toolkit:specPDFs --mermaid.min.js(v11 UMD, 3.16MB) is vendored intotemplates/spec/and the template<head>loads it withtheme:'neutral'(prints cleanly in grayscale). Drop a<pre class="mermaid">block in a.figurediv and it rasterizes to SVG in the existing headless-Chrome pass -- self-contained PDF, no CDN. flowchart, erDiagram, and sequenceDiagram all verified.spec.mdPhase 0 now copies the JS (mandatory), and a.mermaid svgrule keeps wide erDiagrams within US Letter.
Changed
commands/update.md-- one imperative blast-radius line in the boundary block: touch only the field(s) the user named; surface and ask before silently widening a live-record write (Business Rules and Workflows fire, andrun_background_scriptis globally enabled).
Fixed
templates/spec/render.ps1-- renders now run in an isolated, unique--user-data-dirper invocation (cleaned up after). Without it, Chrome hands the render off to the user's already-running instance and returns in ~20ms with NO PDF -- a singleton collision that bit/specbecause it renders Part A then Part B back-to-back. Also switched toStart-Process -Wait.--virtual-time-budgetstays at 10000.
Run /plugin update sn-toolkit@infocenter to pick up the new version.
v1.31.0 -- wrapper down-bridge fast-fail + offline whats-new
Ships the two tail items agreed at the close of v1.30.0: the wrapper-level down-bridge fast-fail deferred as decision 2 of the lazy-bridge design (docs/design-lazy-bridge-probe.md), and an offline path for /sn-toolkit:learn whats-new on installer machines. The wrapper change passes an 18-check smoke suite (no-port-file, stale-pid, forced-file bypass, legacy layout, no-InstanceDir, plus a simulated live server on both a supported and an unsupported protocol); the offline whats-new path was proven both ways against a simulated installed layout. Zero per-prompt token cost.
Changed
bin/sn-agent-api.ps1-- wrapper-level fast-fail on a down bridge:check_connectionon auto transport with no live HTTP server AND no pre-existing legacyagent/requestsdir returns a structuredE_SERVER_NOT_RUNNINGimmediately (thecapabilitiesshape, already mapped inrules/sn-error-codes.md) instead of creatingagent/scratch dirs and polling out the full-TimeoutSeconds.check_sessionon a down apiVersion-7 bridge now verdictsBRIDGE_DOWNin ~0.2s with zero cruft (was ~5s + orphaned dirs). Guard rails: explicit-Transport filebypasses the gate, an already-existingagent/requestsdir keeps the pre-4.3 file-only contract intact, and a live server on an unsupported protocol still fails closed to the file transport.Get-SnServerHealthgains a pid-liveness pre-check before any network I/O -- a stale port file left by a crashed server rejects in ~0.07s instead of burning ~2s on the dead port's connect attempt. Benefits every HTTP-path caller and mirrors the hooks' provenTest-SnServerLivesemantics.docs/design-lazy-bridge-probe.md-- decision 2 updated from DEFERRED to follow-on shipped, with the validation record inline.
Added
sn-toolkit/CHANGELOG.md-- the changelog now SHIPS inside the plugin dir, so/sn-toolkit:learnwhats-new works offline on installer machines for the first time.bin/sn-learn.ps1'sResolve-Changelogalready probed<pluginRoot>/CHANGELOG.mdas its second path, so this needed zero code change -- the release flow now syncs the shipped copy from the canonical root file on every release.
v1.30.0 -- sn-scriptsync 4.5.0 P2 backlog closed: code_search wiring, capabilities synthetic, /sn-toolkit:catalog-test
Closes the sn-scriptsync 4.5.0 carry-over backlog (docs/backlog-snscriptsync-450.md) -- the three P2 items deferred from the v1.26.0 audit batch, plus the flagged stale-comment hazard. Every behavioral claim was live-validated against dev221527 (sn-scriptsync 4.5.0, HTTP protocol apiVersion 5, 40 verbs advertised), and the wrapper transport changes additionally pass a 13-check mock-server suite. Token posture: every edit lives in lazily-loaded command/rule/agent bodies or the wrapper's .NOTES -- zero per-prompt cost.
Added
capabilitiessynthetic command inbin/sn-agent-api.ps1(NOT relayed; HTTP-only; one/api/healthGET, nothing POSTed): returnsresult.commands[]-- the verbs the live server actually supports -- plus.apiVersion,.protocolSupported, and.commandCount, so callers gate features on real capability instead of version integers. A down/absent server returns a structuredE_SERVER_NOT_RUNNING-- fast, noagent/dir littering. The port-file + pid-match health gate was factored into a sharedGet-SnServerHealthused by both the HTTP transport and the synthetic (semantics unchanged;check_sessionregression-tested HEALTHY live). An unsupported future protocol is REPORTED (protocolSupported: false) rather than refused -- the diagnostic that names the mismatch while the transport fails closed. Consumers wired:rules/sn-error-codes.mdand/sn-toolkit:diagnosepre-flight./sn-toolkit:catalog-test(commands/catalog-test.md) -- the 34th slash command: end-to-end catalog item / Record Producer SUBMIT testing through the real browser form, the one loop REST cannot exercise (RP scripts, variable-set client scripts, catalog UI policies, onSubmit validation). Composesnavigate->get_form_state->set_field->take_screenshot->run_ui_action submit->query_recordsverification -> optionalupload_attachmentevidence. Load-bearing claims live-verified before authoring: variables enumerate asIO:<item_option_new.sys_id>keys on the platform catalog view,set_fieldaccepts both the variable name and theIO:key, and/sp?id=exposes nog_form(platform view only). Sub-production only; submit creates real records.
Changed
code_searchwired in as the duplicate-LOGIC discovery pre-pass (the headline 4.5.0 feature, confirmed Pro/Trial/Enterprise-gated -- live call returnsE_DISABLED, HTTP 423): wrapper.NOTEScatalog entry (v2.1.0), a step-4b pre-pass in/sn-toolkit:createwith the silentE_DISABLED->query_recordsLIKE fallback inline, andagents/sn-explorer.md's allow-list widened to include it. Every caller treatsE_DISABLEDas a silent fallback, never a hard failure.- P5 write-guard comments refreshed to the post-4.4.1 reality (
bin/apply-snscriptsync-patch.ps1,CLAUDE.md.template): the destructive overwrite the guard originally targeted is gone; its surviving jobs (suppressing the ~126KB@agentinstructions.mdappend, protecting pre-4.4.1 machines) are now stated with an explicit "NOT dead code, do NOT remove". docs/backlog-snscriptsync-450.mdmarked CLOSED with a shipped-state record per item; command count 33 -> 34 across both READMEs and both manifests;/sn-toolkit:learnOperations group gainscatalog-test.
v1.29.0 -- Fable 5 audit rows 4-7: sessionTitle hook, argument-hint rollout, context-budget lens, Haiku compare-team
Closes out the Fable 5 / Mythos 5 upgrade-audit backlog (docs/audit-2026-06-09-fable5.md, rows 4-7 -- the four S-effort rows left open after v1.28.0's top-3). All four are token-neutral or token-saving: two are pure UI metadata that never touches session context, one extends a lazily-loaded command body, and one demotes mechanical teammate work to Haiku pricing. The session-start change was smoke-tested live both ways (HEALTHY title against dev221527; title-only payload on a never-connected scratch workspace) and frontmatter structure was validated across all 23 edited commands.
Added
hooks/session-start.ps1-- the SessionStart hook now emitssessionTitle(honored by Claude Code >= 2.1.152; older CLIs ignore the field), titling each session by instance + bridge state:SN: dev221527 -- HEALTHY,-- DEGRADED,-- WRONG INSTANCE,-- UNAUTHENTICATED,-- NO TAB,-- BRIDGE DOWN,-- OFFLINE, plus legacy-transport variants. This makes the Desktop + VS Code multi-session pattern navigable by instance at a glance, at zero context tokens. The never-connected silent path keeps its v1.25.7 "no context" contract but now sends a title-only payload (bareSN: <name>, noadditionalContextproperty), and the error catch path titles too.argument-hintfrontmatter on all 23$ARGUMENTS-taking commands (Claude Code 1.0.54+) -- the/menu now advertises each command's expected argument shape at type-time, e.g./sn-toolkit:audit "<update-set-name|sys_id>",/sn-toolkit:switch "<updateset|scope|domain> <target>",/sn-toolkit:inspect "<form|widget|workspace|url> <target> [--attach <table>:<sys_id>] [--no-tn]". UI metadata only -- frontmatter is not injected per-prompt, so the rollout costs zero context tokens. Matches the style thedocsandlearnskills already used, and/sn-toolkit:learnsurfaces the new hints automatically (bin/sn-learn.ps1already reads the key).
Changed
commands/claude-md-audit.md-- new context-budget lens (step 4, local-only, zero instance calls) alongside the existing instance-drift audit: per-file line + approximate-token footprint vs the 200-line lean threshold, naming the largest sections of over-budget files as trim targets; load-reality checks on "auto-loads"/"auto-attaches" claims (a project's.claude/rules/loads, a plugin'srules/does not -- the exact in-repo drift class the v1.28.0 rules fix corrected, now caught per-project); and dead-weight detection for sections duplicating the harness's always-present catalogs. The drift report gains a "Context budget" section and the totals line counts budget flags.commands/compare-team.md-- per-instance teammates demoted Sonnet -> Haiku ($1/$5 vs $3/$15 per MTok; the audit's one "experiment" verdict). The teammate job is mechanical (REST query -> normalize -> write inventory JSON to file) and the Sonnet lead keeps ALL diff synthesis, so the demotion does not move judgment to a weaker model -- the same reasoning as v1.25.8's reviewer demotion. The cost note documents the ~3x-cheaper teammate share and the escape hatch (rerun with Sonnet teammates if inventories come back malformed);diagnose-teamteammates intentionally stay Sonnet, since debate-mode hypothesis work is judgment, not gathering.
v1.28.0 -- Fable 5 audit top-3: rules auto-load fix, agent effort pins, template dedup
Top-3 batch from the Claude Fable 5 / Mythos 5 launch-day upgrade audit (docs/audit-2026-06-09-fable5.md: evergreen gather -> 5-surface match -> 24 candidate rows adversarially verified one-by-one, 16 killed). The audit's focused verdict: the plugin's posture against the new $10/$50 Fable tier ABOVE Opus is defensive and already correct -- every command and agent pins model: sonnet, so no plugin surface inherits Fable pricing in a Fable session, and no Fable upgrade was justified anywhere. The headline that DID survive is a correctness bug: the four path-scoped scripting rules never auto-attached in engagement workspaces.
Fixed
- Rules auto-load:
bin/bootstrap-project.ps1gains a scaffold step copying the four path-scoped rules (conventions.md,sn-scripting.md,sn-testing.md,sn-ui-components.md) into the new project's.claude/rules/, making the designed file-touch-gated attach real for the first time (plugins have no rules component; only a project's own.claude/rules/is honored). The three Agent-API reference rules stay plugin-side as explicit-Read references. Smoke-tested end-to-end. - The three false "auto-loads" claims (
CLAUDE.md.templatex2,agents/sn-explorer.md) now describe the real path-scoped attach mechanism, and the template's directory-structure block documents.claude/rules/.
Changed
effort: mediumfrontmatter pins on all three agents (sn-reviewer,sn-explorer,sn-platform-admin) -- sonnet subagents otherwise default to efforthigh; the saving multiplies across/sn-toolkit:review's up-to-10-parallel fan-out at zero main-thread cache cost.CLAUDE.md.templatedrops the duplicated "Plugin Slash Commands (most used)" block (~90 tokens at every session launch in every scaffolded project, drift-prone;/sn-toolkit:learnis the drift-free catalog).rules/conventions.mdpaths:globs tightened from**/*.md+**/*.jsoncatch-alls to code files plus**/agent/**/*.json.
Added
docs/audit-2026-06-09-fable5.md-- the full audit report (7 surviving recommendations with rows 4-7 still open, 16 kills grouped by reason, Fable/Mythos posture analysis, and the live mid-run cost incident that led to model-pinning the audit engine itself).
Existing workspaces note: the rules copy runs at bootstrap, so projects scaffolded before v1.28.0 won't have .claude/rules/ populated -- copy the four rules from the plugin's rules/ once, or re-run bootstrap into a fresh workspace.