tableau-route
A thin router over the file-based workflow contract. It reads STATE.md in the
analyst's project and tells them which one skill to run next — nothing more.
This skill is a router only. It NEVER invokes another skill inline. Running the next skill here would share this conversation's context and defeat the entire point of the plugin (each skill must run in its own fresh conversation). Your job ends at recommending the next skill and telling the analyst to run it themselves.
How to run
Determine the analyst's project directory (the directory that contains, or should contain,
STATE.md). Default to the current working directory.Run the router script and capture its output:
python "${CLAUDE_PLUGIN_ROOT}/skills/tableau-route/scripts/route.py" "<project-dir>"(Use
python3ifpythonis unavailable.) The script readsSTATE.md, applies the ordering rule fromCONTRACT.md, and prints the recommended next skill plus a one-line reason. It is pure and read-only — it does not modify any files.Relay the script's recommendation to the analyst, then stop. Tell them to open a fresh conversation and invoke the recommended skill themselves (e.g. "Run
tableau-datanext"). Do not call the recommended skill yourself.
Interpreting the result
The script reports one of four situations:
- fresh project (no
STATE.md) → recommendstableau-initto scaffold the project. - a step is ready → recommends that step's skill (the first step whose status
is
pendingorstale, with its required inputs satisfied). - blocked → a required upstream artifact is unresolved or missing on disk; the script points at the upstream skill to run first.
- done → every step is
approvedorskipped; point the analyst at their deliverables undermock-version/v_N/.
If STATE.md looks malformed or the recommendation is surprising, show the
analyst the relevant part of STATE.md and refer them to CONTRACT.md (the
canonical schema) rather than guessing.
The full schema and the ordering / staleness / versioning rules live in
CONTRACT.mdat the repo root. This skill deliberately restates only what it needs;route.pyis the executable mirror of that contract.