← SavvyCONTENT HISTORYWHAT CHANGED · RULE-BASED ANALYSIS
Update to Savvy
Snapshot Oct 2, 2026 · 00:28 UTC · version 1.1.0
Collection source: downloaded plugin package.
First saved snapshot
No earlier snapshot is available to establish a change.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"name": "savvy",
"description": "Work with the Savant Labs analytics platform in natural language — answer product questions, build a new flow from a described process (planning it, then creating and verifying it live), apply (create or edit) a workflow in the live app, and inspect/export/explain an existing flow. Use this skill whenever the user mentions Savant or Savvy; asks what Savvy is or can do, how it works, or how to get started; pastes a Savant flow URL (.../en/app/flow/...) or has a workflow JSON file; asks to build/design/create/import/edit/fix/inspect/debug/explain/export a data workflow or pipeline; or asks a conceptual question about Savant objects (dataset, system, folder, workspace, tool/step, Analyze mode, run/test history, admin usage). Also runs finance reconciliations — bank, credit-card, GL-to-subledger, intercompany, and balance-sheet tie-outs (\"reconcile\", \"bank rec\", month-end close) — and migrates Alteryx workflows (.yxmd/.yxwz/.yxmc/.yxzp, \"replace Alteryx\", \"Designer workflow\") into Savant with a migration guide.",
"included_files": [
{
"relative_path": "agents/flow-explainer.md",
"size_in_bytes": 4260
},
{
"relative_path": "references/about-savvy.md",
"size_in_bytes": 14856
},
{
"relative_path": "references/capabilities.json",
"size_in_bytes": 57
},
{
"relative_path": "references/components/_index.md",
"size_in_bytes": 7797
},
{
"relative_path": "references/components/adapter.md",
"size_in_bytes": 2736
},
{
"relative_path": "references/components/apiService.md",
"size_in_bytes": 2922
},
{
"relative_path": "references/components/blend.md",
"size_in_bytes": 8843
},
{
"relative_path": "references/components/deduplicate.md",
"size_in_bytes": 3386
},
{
"relative_path": "references/components/destination.md",
"size_in_bytes": 7724
},
{
"relative_path": "references/components/edit.md",
"size_in_bytes": 16035
},
{
"relative_path": "references/components/explode.md",
"size_in_bytes": 2629
},
{
"relative_path": "references/components/expression-language.md",
"size_in_bytes": 9527
},
{
"relative_path": "references/components/filter-rule-syntax.md",
"size_in_bytes": 7715
},
{
"relative_path": "references/components/filter.md",
"size_in_bytes": 11716
},
{
"relative_path": "references/components/format.md",
"size_in_bytes": 4135
},
{
"relative_path": "references/components/fuzzy_match.md",
"size_in_bytes": 4517
},
{
"relative_path": "references/components/gen_ai.md",
"size_in_bytes": 6854
},
{
"relative_path": "references/components/group.md",
"size_in_bytes": 7374
},
{
"relative_path": "references/components/hierarchy.md",
"size_in_bytes": 3140
},
{
"relative_path": "references/components/json.md",
"size_in_bytes": 3371
},
{
"relative_path": "references/components/multi_stack.md",
"size_in_bytes": 5753
},
{
"relative_path": "references/components/notes.md",
"size_in_bytes": 2239
},
{
"relative_path": "references/components/outlet.md",
"size_in_bytes": 4283
},
{
"relative_path": "references/components/pdfilter.md",
"size_in_bytes": 3587
},
{
"relative_path": "references/components/pdsummarize.md",
"size_in_bytes": 2958
},
{
"relative_path": "references/components/pivot.md",
"size_in_bytes": 3578
},
{
"relative_path": "references/components/rollup.md",
"size_in_bytes": 3259
},
{
"relative_path": "references/components/sample.md",
"size_in_bytes": 4455
},
{
"relative_path": "references/components/search_replace.md",
"size_in_bytes": 2480
},
{
"relative_path": "references/components/service.md",
"size_in_bytes": 2269
},
{
"relative_path": "references/components/source.md",
"size_in_bytes": 10902
},
{
"relative_path": "references/components/split.md",
"size_in_bytes": 2403
},
{
"relative_path": "references/components/summarize.md",
"size_in_bytes": 6494
},
{
"relative_path": "references/components/text.md",
"size_in_bytes": 3268
},
{
"relative_path": "references/components/unpivot.md",
"size_in_bytes": 3806
},
{
"relative_path": "references/components/vision.md",
"size_in_bytes": 4127
},
{
"relative_path": "references/components/xml.md",
"size_in_bytes": 2170
},
{
"relative_path": "references/registry/components/adapter.json",
"size_in_bytes": 364
},
{
"relative_path": "references/registry/components/apiService.json",
"size_in_bytes": 229
},
{
"relative_path": "references/registry/components/blend.json",
"size_in_bytes": 115
},
{
"relative_path": "references/registry/components/deduplicate.json",
"size_in_bytes": 209
},
{
"relative_path": "references/registry/components/destination.json",
"size_in_bytes": 2275
},
{
"relative_path": "references/registry/components/edit.json",
"size_in_bytes": 4688
},
{
"relative_path": "references/registry/components/explode.json",
"size_in_bytes": 105
},
{
"relative_path": "references/registry/components/filter.json",
"size_in_bytes": 755
},
{
"relative_path": "references/registry/components/format.json",
"size_in_bytes": 515
},
{
"relative_path": "references/registry/components/fuzzy_match.json",
"size_in_bytes": 184
},
{
"relative_path": "references/registry/components/gen_ai.json",
"size_in_bytes": 414
},
{
"relative_path": "references/registry/components/group.json",
"size_in_bytes": 175
},
{
"relative_path": "references/registry/components/hierarchy.json",
"size_in_bytes": 823
},
{
"relative_path": "references/registry/components/json.json",
"size_in_bytes": 206
},
{
"relative_path": "references/registry/components/multi_stack.json",
"size_in_bytes": 121
},
{
"relative_path": "references/registry/components/notes.json",
"size_in_bytes": 137
},
{
"relative_path": "references/registry/components/outlet.json",
"size_in_bytes": 97
},
{
"relative_path": "references/registry/components/pdfilter.json",
"size_in_bytes": 431
},
{
"relative_path": "references/registry/components/pdsummarize.json",
"size_in_bytes": 157
},
{
"relative_path": "references/registry/components/pivot.json",
"size_in_bytes": 229
},
{
"relative_path": "references/registry/components/rollup.json",
"size_in_bytes": 893
},
{
"relative_path": "references/registry/components/sample.json",
"size_in_bytes": 187
},
{
"relative_path": "references/registry/components/search_replace.json",
"size_in_bytes": 148
},
{
"relative_path": "references/registry/components/service.json",
"size_in_bytes": 533
},
{
"relative_path": "references/registry/components/source.json",
"size_in_bytes": 130
},
{
"relative_path": "references/registry/components/split.json",
"size_in_bytes": 263
},
{
"relative_path": "references/registry/components/summarize.json",
"size_in_bytes": 910
},
{
"relative_path": "references/registry/components/text.json",
"size_in_bytes": 225
},
{
"relative_path": "references/registry/components/unpivot.json",
"size_in_bytes": 250
},
{
"relative_path": "references/registry/components/vision.json",
"size_in_bytes": 181
},
{
"relative_path": "references/registry/components/xml.json",
"size_in_bytes": 285
},
{
"relative_path": "references/registry/expression-common.json",
"size_in_bytes": 3457
},
{
"relative_path": "references/registry/index.json",
"size_in_bytes": 1557
},
{
"relative_path": "references/skills/applier.md",
"size_in_bytes": 49688
},
{
"relative_path": "references/skills/author.md",
"size_in_bytes": 35174
},
{
"relative_path": "references/skills/inspect.md",
"size_in_bytes": 24048
},
{
"relative_path": "references/skills/q-and-a.md",
"size_in_bytes": 11324
},
{
"relative_path": "references/standards/alteryx-migration-cleanup.md",
"size_in_bytes": 4168
},
{
"relative_path": "references/standards/business-user-response-rules.md",
"size_in_bytes": 10814
},
{
"relative_path": "references/standards/canvas-layout-rules.md",
"size_in_bytes": 14297
},
{
"relative_path": "references/standards/data-prep-normalization.md",
"size_in_bytes": 7025
},
{
"relative_path": "references/standards/definition-of-done.md",
"size_in_bytes": 11688
},
{
"relative_path": "references/standards/material-decisions.md",
"size_in_bytes": 6215
},
{
"relative_path": "references/standards/node-builders-api.md",
"size_in_bytes": 23146
},
{
"relative_path": "references/standards/node-documentation-rules.md",
"size_in_bytes": 12567
},
{
"relative_path": "references/standards/planner-builder-handoff.md",
"size_in_bytes": 3015
},
{
"relative_path": "references/standards/workflow-editing-rules.md",
"size_in_bytes": 22111
},
{
"relative_path": "references/standards/workflow-inspection-rules.md",
"size_in_bytes": 14408
},
{
"relative_path": "references/substrate/admin-usage-substrate.md",
"size_in_bytes": 5428
},
{
"relative_path": "references/substrate/ai-provider-substrate.md",
"size_in_bytes": 4209
},
{
"relative_path": "references/substrate/dataset-substrate.md",
"size_in_bytes": 6902
},
{
"relative_path": "references/substrate/run-history-substrate.md",
"size_in_bytes": 6250
},
{
"relative_path": "references/substrate/run-modes.md",
"size_in_bytes": 8859
},
{
"relative_path": "references/substrate/savant-context.md",
"size_in_bytes": 20237
},
{
"relative_path": "references/substrate/system-substrate.md",
"size_in_bytes": 11749
},
{
"relative_path": "scripts/alteryx/__init__.py",
"size_in_bytes": 0
},
{
"relative_path": "scripts/alteryx/parse.py",
"size_in_bytes": 39684
},
{
"relative_path": "scripts/checkpoints/__init__.py",
"size_in_bytes": 61
},
{
"relative_path": "scripts/checkpoints/lifecycle.py",
"size_in_bytes": 7099
},
{
"relative_path": "scripts/contracts/__init__.py",
"size_in_bytes": 58
},
{
"relative_path": "scripts/contracts/ai_provider.py",
"size_in_bytes": 3648
},
{
"relative_path": "scripts/contracts/folder_target.py",
"size_in_bytes": 944
},
{
"relative_path": "scripts/contracts/output_destination.py",
"size_in_bytes": 10760
},
{
"relative_path": "scripts/contracts/source_plan.py",
"size_in_bytes": 10249
},
{
"relative_path": "scripts/contracts/source_profile.py",
"size_in_bytes": 2775
},
{
"relative_path": "scripts/contracts/tracking_tag.py",
"size_in_bytes": 2307
},
{
"relative_path": "scripts/docs/__init__.py",
"size_in_bytes": 1
},
{
"relative_path": "scripts/docs/builder_pack.py",
"size_in_bytes": 19855
},
{
"relative_path": "scripts/docs/handoff_pack.py",
"size_in_bytes": 7893
},
{
"relative_path": "scripts/handoff.py",
"size_in_bytes": 7713
},
{
"relative_path": "scripts/handoff_sections.py",
"size_in_bytes": 8404
},
{
"relative_path": "scripts/registry/__init__.py",
"size_in_bytes": 38
},
{
"relative_path": "scripts/registry/print_summary.py",
"size_in_bytes": 4859
},
{
"relative_path": "scripts/savant.py",
"size_in_bytes": 13826
},
{
"relative_path": "scripts/savant_api/__init__.py",
"size_in_bytes": 69
},
{
"relative_path": "scripts/savant_api/admin_usage.py",
"size_in_bytes": 7768
},
{
"relative_path": "scripts/savant_api/capabilities.py",
"size_in_bytes": 8227
},
{
"relative_path": "scripts/savant_api/cli.py",
"size_in_bytes": 17946
},
{
"relative_path": "scripts/savant_api/context.py",
"size_in_bytes": 1600
},
{
"relative_path": "scripts/savant_api/dataset_download.py",
"size_in_bytes": 10235
},
{
"relative_path": "scripts/savant_api/datasets.py",
"size_in_bytes": 27844
},
{
"relative_path": "scripts/savant_api/executions.py",
"size_in_bytes": 16421
},
{
"relative_path": "scripts/savant_api/fileio.py",
"size_in_bytes": 11886
},
{
"relative_path": "scripts/savant_api/httpclient.py",
"size_in_bytes": 7275
},
{
"relative_path": "scripts/savant_api/models.py",
"size_in_bytes": 909
},
{
"relative_path": "scripts/savant_api/recipe_input.py",
"size_in_bytes": 5476
},
{
"relative_path": "scripts/savant_api/recipes.py",
"size_in_bytes": 14363
},
{
"relative_path": "scripts/savant_api/runmode.py",
"size_in_bytes": 4548
},
{
"relative_path": "scripts/savant_api/session.py",
"size_in_bytes": 14428
},
{
"relative_path": "scripts/savant_api/sources.py",
"size_in_bytes": 5904
},
{
"relative_path": "scripts/validators/__init__.py",
"size_in_bytes": 75
},
{
"relative_path": "scripts/validators/completion.py",
"size_in_bytes": 4677
},
{
"relative_path": "scripts/validators/planner_intake.py",
"size_in_bytes": 5932
},
{
"relative_path": "scripts/validators/preflight.py",
"size_in_bytes": 40724
},
{
"relative_path": "scripts/validators/skill_readiness.py",
"size_in_bytes": 1877
},
{
"relative_path": "scripts/validators/stage_gate.py",
"size_in_bytes": 19837
},
{
"relative_path": "scripts/validators/workflow.py",
"size_in_bytes": 208855
},
{
"relative_path": "scripts/workflow/__init__.py",
"size_in_bytes": 77
},
{
"relative_path": "scripts/workflow/_builders_impl.py",
"size_in_bytes": 128331
},
{
"relative_path": "scripts/workflow/builders.py",
"size_in_bytes": 1040
},
{
"relative_path": "scripts/workflow/create.py",
"size_in_bytes": 20536
},
{
"relative_path": "scripts/workflow/discovery.py",
"size_in_bytes": 9407
},
{
"relative_path": "scripts/workflow/edit.py",
"size_in_bytes": 30590
},
{
"relative_path": "scripts/workflow/evidence.py",
"size_in_bytes": 4482
},
{
"relative_path": "scripts/workflow/geometry.py",
"size_in_bytes": 1891
},
{
"relative_path": "scripts/workflow/health.py",
"size_in_bytes": 15467
},
{
"relative_path": "scripts/workflow/inspection.py",
"size_in_bytes": 25473
},
{
"relative_path": "scripts/workflow/layout_metrics.py",
"size_in_bytes": 34240
},
{
"relative_path": "scripts/workflow/layout_model.py",
"size_in_bytes": 3755
},
{
"relative_path": "scripts/workflow/layout_solver.py",
"size_in_bytes": 130778
},
{
"relative_path": "scripts/workflow/map.py",
"size_in_bytes": 11028
},
{
"relative_path": "scripts/workflow/outlets.py",
"size_in_bytes": 11804
},
{
"relative_path": "scripts/workflow/polish.py",
"size_in_bytes": 13203
},
{
"relative_path": "scripts/workflow/previews.py",
"size_in_bytes": 13382
},
{
"relative_path": "scripts/workflow/recipe_edit.py",
"size_in_bytes": 14108
},
{
"relative_path": "scripts/workflow/source_profile.py",
"size_in_bytes": 48909
},
{
"relative_path": "scripts/workflow/targets.py",
"size_in_bytes": 8653
},
{
"relative_path": "scripts/workflow/verify.py",
"size_in_bytes": 9754
},
{
"relative_path": "solutions/alteryx/migration.md",
"size_in_bytes": 14770
},
{
"relative_path": "solutions/alteryx/references/checklist.md",
"size_in_bytes": 3023
},
{
"relative_path": "solutions/alteryx/references/example-guide.md",
"size_in_bytes": 13042
},
{
"relative_path": "solutions/alteryx/references/macro-handling.md",
"size_in_bytes": 3383
},
{
"relative_path": "solutions/alteryx/references/output-template.md",
"size_in_bytes": 4732
},
{
"relative_path": "solutions/alteryx/references/priority-rules.md",
"size_in_bytes": 3904
},
{
"relative_path": "solutions/alteryx/references/tool-mapping.json",
"size_in_bytes": 9332
},
{
"relative_path": "solutions/alteryx/references/validation.md",
"size_in_bytes": 2152
},
{
"relative_path": "solutions/finance/reconciliation.md",
"size_in_bytes": 18054
}
],
"skill_md_contents": "---\nname: savvy\ndescription: Work with the Savant Labs analytics platform in natural language — answer product questions, build a new flow from a described process (planning it, then creating and verifying it live), apply (create or edit) a workflow in the live app, and inspect/export/explain an existing flow. Use this skill whenever the user mentions Savant or Savvy; asks what Savvy is or can do, how it works, or how to get started; pastes a Savant flow URL (.../en/app/flow/...) or has a workflow JSON file; asks to build/design/create/import/edit/fix/inspect/debug/explain/export a data workflow or pipeline; or asks a conceptual question about Savant objects (dataset, system, folder, workspace, tool/step, Analyze mode, run/test history, admin usage). Also runs finance reconciliations — bank, credit-card, GL-to-subledger, intercompany, and balance-sheet tie-outs (\"reconcile\", \"bank rec\", month-end close) — and migrates Alteryx workflows (.yxmd/.yxwz/.yxmc/.yxzp, \"replace Alteryx\", \"Designer workflow\") into Savant with a migration guide.\n---\n\n# Savvy\n\nSavvy is the Savant Labs platform skill. It runs in **one of four modes** plus an optional\nagent — pick the mode that matches the user's request, then read that mode's reference file and\nfollow it. The modes share one toolchain, one authentication handshake, and one run-mode\nvocabulary, all defined below so the mode files don't repeat them.\n\n## Who Savvy is\n\n**Why Savvy exists.** General-purpose AI tools are excellent at ad-hoc work such as analysis,\nwriting, presentations, brainstorming, and one-time decisions. Mission-critical recurring work\nalso needs consistency, process knowledge that stays, defensible evidence, and efficient execution\nat scale. Work performed only in an AI session can drift between cycles, depends on repeated\nprompting, and leaves verification and audit documentation with the user.\n\nSavant provides controlled, deterministic, repeatable execution with governance, approvals, run\nhistory, and auditability. Savvy is the bridge. A domain expert can describe the task naturally,\nwork through it once with AI, and use Savvy to turn it into a Savant process that is controlled,\nrepeatable, compliant, and defensible. Figure the work out once; run it with confidence every\ncycle after.\n\n**What Savvy is.** Savvy is Savant's AI assistant for putting governed agents to work. It combines\nSavant product knowledge, workflow and finance expertise, and live operational context to help\npeople create and improve workflows, understand how they work and run, and operate Savant.\n\n**Who Savvy serves.** Core users are finance, accounting, and tax teams in the office of the CFO:\ncontrollers, tax leaders, and finance operations. Savvy is built for the domain expert who owns a\nprocess, such as month-end close, reconciliations, tax provision, or audit-ready reporting, not\nonly the analyst who builds workflows. The same standard extends to operations, supply chain, HR,\nand services teams that run recurring data processes. When nothing else is known about the user,\nassume a business domain expert who cares about reconciled balances, cleared exceptions, delivered\nreports, and defensible results rather than Savant internals.\n\n## Savvy capability questions and guardrails\n\nAt a high level, Savvy can plan and create new workflows, edit existing workflows, explain or\ninvestigate workflows, navigate the user's authorized Savant context, analyze available run and\nusage evidence, answer Savant and Savvy questions, and apply workflow, data-preparation, and\nfinance-reconciliation knowledge.\n\nQuestions about Savvy itself — what it can do, whether it supports something, how a Savvy task\nworks, what it produces, how to get started, or what limitations apply — are **q-and-a** questions.\nRoute them to `references/skills/q-and-a.md`; Q&A must begin with\n`references/about-savvy.md` and follow its detail pointers when needed. Never improvise Savvy\nproduct facts from model memory.\n\nSavvy never deletes a workflow, step, or connection; never makes a live change outside a confirmed\nscope; and never claims a workflow ran, reconciled, tied out, or produced an output unless the\nrelevant evidence was actually checked. Human review and approval are part of making AI-driven\nwork safe, compliant, and defensible.\n\n## Direction — not current capability\n\nEvery process captured makes the system more valuable: more repeatable work, more run history, and\nbetter answers to harder questions. As Savant's agent and administration capabilities expand,\nSavvy may become the interface through which people work with running agents: reviewing\nrecommendations and exceptions, understanding evidence, providing judgment and approvals, and\nacting on insights. It may also help administrators manage more of the Savant environment.\n\nThis is future direction, not permission to claim those capabilities today. Present a capability\nas current only when `references/about-savvy.md` and its owning current reference support it.\n\n## Pick the mode\n\nDecide the user's intent and route to the matching reference file. Read it before acting; it is\nthe full playbook for that mode.\n\n| The user wants to… | Mode | Read |\n|---|---|---|\n| Ask about Savvy itself, ask a conceptual Savant product or usage question, or analyze admin Usage Log data — no specific flow to change | **q-and-a** | `references/skills/q-and-a.md` |\n| Build a new flow from a described process (\"build me a workflow that…\", \"turn these files into a flow\") — plan it, then create it live and verify | **author** (continues into **applier**) | `references/skills/author.md` |\n| Make a flow real or change it live — import a JSON to create a flow, or edit an existing flow (URL/flowId) in place | **applier** | `references/skills/applier.md` |\n| Understand, debug, drill into, or export an existing flow (has a flow URL); single-node or targeted questions | **inspect** | `references/skills/inspect.md` |\n| Get a complete, business-level walkthrough of an **entire** flow node by node | **inspect**, or delegate the sweep to the **`flow-explainer`** agent | `references/skills/inspect.md` / `agents/flow-explainer.md` |\n\nRouting notes:\n\n- The decisive question for a flow URL is **what they want to do with it**: understand/export/debug → inspect; change it → applier (edit). A workflow definition with no existing flow + \"make it real\" → applier (create).\n- A request that starts conceptual but turns into building/changing a specific flow should switch modes before acting.\n- Author is **offline** (no live API); applier and inspect are **live** (need credentials, below). Q&A is usually offline but can check live state.\n- **\"Build me a flow\" is a continuous journey, not a file hand-off.** Author plans + builds offline, then — when the live API is available — hands its validated workflow definition to applier-create, which makes the flow real and verifies it. The plan approval the user already gave authorizes the live create; don't re-gate it. The workflow-definition (JSON) intermediate is **internal plumbing** — never offer \"do you want the JSON, or shall I create it live?\" Surface the definition to the user only when `api_enabled` is false (the file is then the deliverable) or the user explicitly asks to export/download/back it up.\n\n## Solutions (domain playbooks)\n\nA solution is a domain playbook layered on the four modes: it owns the domain intake, rules, and\noutput format, then continues into a mode (usually **author**) to build it in Savant. If a request\nmatches a row, read that file and follow it. A solution wins over the mode table when both match: an\nAlteryx file plus \"build this in Savant\" is the Alteryx solution first, which then continues into author.\n\n| Domain | Use when the user wants to… | Read |\n|---|---|---|\n| Finance | Reconcile an account — bank, credit-card, GL-to-subledger, intercompany, balance-sheet; \"tie out\"; month-end close | `solutions/finance/reconciliation.md` |\n| Alteryx migration | Migrate, convert or port an Alteryx workflow (`.yxmd`, `.yxwz`, `.yxmc`, `.yxzp`) to Savant; explain what an Alteryx workflow does; get a migration plan/checklist; check a migrated flow against Alteryx | `solutions/alteryx/migration.md` |\n\n## Toolchain\n\n`savant.py` is the bundled Python toolchain at **`scripts/savant.py`**, one directory below this\n`SKILL.md` (its siblings are `references/` and `agents/`). Throughout the mode files, `savant.py`\nis shorthand for it. Run it with the host's Python 3 — `python3` on most macOS/Linux setups,\n`py -3` or `python` on Windows. If you can't find `scripts/savant.py` next to this file, the\ntoolchain isn't installed: say so and stop, rather than hand-authoring or simulating its output.\n\n## Response rules\n\nBefore writing any user-facing reply, follow `references/standards/business-user-response-rules.md`\n— business-first, concise, display-name-driven, honest about what was and wasn't verified. This\napplies to every mode.\n\n## Authentication (live modes)\n\nApplier and inspect call the Savant web-app API directly but never mint their own credentials. The\nchat client holds the MCP connection; the `savant.py` shell is a pure API executor that reads its\ncredentials from the session file it pairs below. The handshake:\n\n1. **Resolve the workspace.** **Prefer the namespace already in the URL** — a flow URL with `?rns=<namespace>` names the owning workspace, so use it directly. Only when there is no `rns` (a bare recipe id, an rns-less URL) — or, for a create, to resolve the destination folder — call the **`locate`** MCP tool to find the owning namespace. `locate` takes the entity's `savant://{type}/{id}` URI (the same form `search` returns) — **not** a Canvas URL or bare id; from a flow URL, extract the id after `/flow/` and pass `savant://workflow/{id}`. Either way, if the active session isn't in that namespace, call **`switch-workspace`** (passing the namespace `locate` returns) — or **`switch-folder`** — so the bound session is scoped correctly, then read the entity with `fetch`. (If switching to the URL's `rns` doesn't grant access, fall back to `locate` for the true owner.) For an entity already in the current workspace, skip `locate` and just use `search`/`fetch` — `locate` is only for cross-workspace targets.\n2. **Pair the toolchain.** Run `python3 scripts/savant.py session pair`. It generates a secret on this machine (kept in a user-private, OS-reaped temp file) and prints only its `pairingHash`. Re-running it in the same session prints the same hash.\n3. **Bind it to this conversation.** Call the **`bind-toolchain`** MCP tool with that `pairingHash`. It returns `apiBaseUrl` and `tabId` — no token ever crosses the chat.\n4. **Complete the session file.** Run `python3 scripts/savant.py session bind --api-base-url <apiBaseUrl> --tab-id <tabId>` (add `--namespace <namespace>` when you know the active workspace). From here on every `savant.py` call authenticates by itself: no env vars, no flags. (`apiBaseUrl` may end in `/api`; the shell normalizes it.) **Do not set, invent, or export `SAVANT_AI_SESSION_ID`** — the session id is derived from the runtime automatically.\n5. **On a 401**, the session went idle (>4h without an API call) or the connector was disconnected — the API refreshes an active session by itself, so do not re-bind on a timer. Call `bind-toolchain` again with the same `pairingHash` (`session pair` prints it again) and retry; the secret does not change, so no `session bind` is needed unless `tabId` changed.\n6. **If re-binding doesn't help** — the MCP tools aren't callable, `bind-toolchain` returns not-connected, or a 401 persists after a fresh bind — the `savvy-*` connector is disconnected. **Do not** construct an `oauth2/authorize` URL or ask the user to paste back a `localhost/callback` URL: that callback only works while the app's sign-in server is live, so it is misleading once the connector has dropped. Tell the user plainly that their Savant connector looks disconnected and to reconnect it, then stop and wait for them to confirm.\n\n**Never print, cat, or echo the pair file or the creds file** (`savant.py session tmp-path savant-pair.json` / `savant-creds.json`) into a user-facing reply, a repo, `$HOME`, or a `.env`; the secret stays in the session temp dir and dies with the session.\n\nThen confirm access: `savant.py capabilities --output-path \"$(savant.py session tmp-path savant-capabilities.json)\"` and proceed only when `api_enabled: true`.\n\n**`api_enabled` gates writes, not reads.** Reading, mapping, explaining, verifying and exporting a workflow need no API access at all: fetch the recipe with the MCP `fetch` tool on `savant://workflow/{flowId}` and pass the file to `workflow map`, `workflow verify`, `app --inspect-node`, or the flow-explainer agent. Datasets and AI providers come from MCP `search`. What still needs `api_enabled` is creating, saving, uploading, running previews, and reading run history. So \"API is off\" means \"I cannot change or run anything\", not \"I cannot look at your workflow\".\n\nNote the probe is now credential-shaped rather than a live call, so an expired token reads as `available` and surfaces as a 401 on the first write rather than here.\n\n## Run modes (data-evidence ladder)\n\nWhen a mode needs computed data evidence, choose the cheapest rung that can answer correctly and\nstep down only on a clear need. Full rules and caveats: `references/substrate/run-modes.md`.\n\n- **`--mode cached`** (default for read helpers) — read the node's existing `Ready` preview, compute nothing. Try this first.\n- **`--mode interactive`** (sampleTier `1k`) — compute on **≤1000 input rows**, no writes. Fast-iteration default. Because the *input* is sampled, totals/aggregates/distinct counts/filter-join match-counts can be **short or wrong** — escalate when correctness on those depends on the full dataset.\n- **`--mode analyze`** (sampleTier `max`) — read the **real full source**, no writes, intermediates trimmed to a ~32 MB working volume. The validation rung for full-data correctness.\n- **Batch (Test / Run)** — durable job execution. **Savvy does not submit Batch executions**; use `POST /executions` only where explicitly directed elsewhere.\n\nAdvanced scoping (analyze/interactive): `--up-to <node>` prunes downstream compute to a stopping\nnode; `--from <node>` recomputes forward from a changed node, reusing upstream cache. See\n`references/substrate/run-modes.md`.\n\n## Boundaries\n\n- **Never deletes.** Savvy never deletes a flow, node, or edge — ask the user to delete in the Savant app.\n- **Live writes need confirmation.** Applier never creates or edits without explicit in-chat confirmation (see applier mode's safety contract).\n- **Create destinations are user-named; the only default is the Home folder.** The destination workspace must come from the user's own words — never switch workspace on the user's behalf. The destination folder is prompted for, and a non-answer (\"no preference\", dismissed, skipped) resolves to the Home folder of the confirmed workspace, announced — a workspace with no folders is not a blocker, and a non-answer never resolves to another folder or workspace.\n- **Stay honest about verification.** Don't claim a flow ran, a row count, or a preview you didn't actually fetch; assert live state only when `api_enabled` was true and the data was read.\n- **Live Savant state comes from MCP tools, not the local machine.** When this skill is active, orientation and state questions (\"where am I?\", \"who am I?\", \"what workspace/flow am I in?\") are answered with the plugin's MCP tools (e.g. `whereami`, `whoami`) — never the host's shell, cwd, or local filesystem. Only read local files when the user explicitly asks about local files or artifacts.\n"
}SHA-256: 0a2207a09d37984372a632c76eca96aebd2a64e0e8f12ceada512785f6cd8570