diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d07f482..2ab80d8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - **`pipelex-inputs` uploads your files where they lie, and a method's folder keeps only `inputs.json` (Breaking)**: the skill no longer copies your files into `inputs/` beside the method or writes `inputs.prepared.json` there; it uploads each file from where you keep it, an Office file as the PDF it exports into a temporary directory, and writes the `pipelex-storage://` address it gets back into `inputs.json`, which `pipelex-run` then runs as it stands, sending a value that still names a local file back to `pipelex-inputs` to be uploaded first. `pipelex-synthetic-inputs` makes its files in a fresh temporary directory by default, on its own too, and reports their path and their name among your organization's files, so anything that read the copies under `inputs/` or a method folder's `inputs.prepared.json` now reads the addresses in `inputs.json`, which resolve only inside the organization that uploaded the files. A `pipelex-lab` case is the exception and keeps its copies under `cases//inputs/` with its prepared file beside them, so that it runs from any clone, and folders an earlier release prepared are not migrated. - **The validation hook sends the method's tree**: the `check.mjs` bundle every target runs on a `.mthds` edit now sends the edited file's method to validation as the tree a run would send, rooted at the nearest `METHODS.toml`, every file the MTHDS membership rule keeps under its root rather than only its `.mthds` files and the templates its steps name. Names starting with a dot, such as `.env`, a run's inputs file, and what a `.gitignore` inside the tree or the manifest's `exclude` keeps out stay on your machine, and so does a file the hook's secret screen finds, named like a key or credentials file or holding a private key or a provider's key, which the verdict's note names without quoting it; a bundle or manifest that looks like a secret sends nothing, under a note. A `.gitignore` above the tree, such as a repository's root one, still keeps nothing out, and the screen recognizes only well-known shapes, so keep keys and credentials out of a method's directory, or list them in a `.gitignore` inside it. A tree holding a symbolic link, or past the hook's size caps, still passes the validation silently. - **The validation hook names each problem item of a refused method (Breaking)**: when the server sends no Markdown with an invalid verdict, the block reason the `check.mjs` bundle builds now gives every problem item of the verdict's `errors[]` a line of its own, with its code, its sentence and where it happened, such as its pipe and its file, and the item's suggested fix beneath it, where against a server speaking the MTHDS problem document it named no item at all. A server still answering the older shape is no longer read: the bundle ignores its `validation_errors[]`, so when such a server also ignores the `render` request, the block reason holds the verdict's message alone and names none of its faults. It is rebuilt on `@pipelex/sdk` 0.53.0, with `@pipelex/tools-wasm` still at 0.6.0, and its lint, its format and the request its validate stage sends are unchanged, except that its `User-Agent` names 0.53.0. +- **The skills read the Pipelex tools' errors as problem documents (Breaking)**: every skill now reads a failed tool call by its problem's `code`, `domain`, `retry` and `next_step`, a verdict's faults as `errors[]` items, its warnings as problem items such as `pipelex.docgen.template_warning`, and a failed run by its `run_error`, which is what the workshop sends from the release that moves its errors to the MTHDS problem document, instead of the `class`, `retryable`, `hint` and `kind` of an error, `validation_errors[]` outside the catalog's save and publish, and a run's `failure_message`, which it no longer sends. So a missing or refused key, a role, the organization's credit or an unreachable API stops a skill with the tool's next step relayed verbatim, the catalog tells an unknown id from a link naming another method, a version suffix and an empty stored source by their codes, `pipelex-inputs` reads a preparation failure by its code, and a failed run keeps the support line the tool's summary ends with; use these skills with a workshop that sends problem documents. ### Fixed diff --git a/CLAUDE.md b/CLAUDE.md index 76e4b3cf..6e7cd68f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -78,10 +78,10 @@ skills/ # SOURCE OF TRUTH for static (non-templated) skil ├── pipelex-explain/references/ # not-on-disk.md — a catalog id or a published address, read before the first call on one ├── pipelex-design/references/ # stepwise.md — signature-driven construction; re-entry.md — a structural change to an existing method; each read on its condition (the language reference it reads before every write is the shared writing-mthds.md) ├── pipelex-synthetic-inputs/references/ # pdf.md, png.md, office.md — runnable recipes, executed by tests/recipes; photograph.md — a photograph generated by `gpt-image-2` through the workshop, read at step 1; venv.md — the venv rung, read when `uv` is not on PATH, its block executed by tests/recipes too -├── pipelex-inputs/references/ # synthetic.md, user-data.md — the strategies and their worked examples, synthetic.md also the `kind: "test"` the factory's files are uploaded with; published-address.md — a method_ref target; prepare-errors.md — prepare's input_domain errors, the size limit's terminal branch included; each read on its condition -├── pipelex-run/references/ # by-id.md — a catalog id target, its version forms and which version ran, read at step 1; published-address.md — a method_ref target, read at step 1; failed-run.md — the failure routing, read before a failed run is routed; linked-run.md — a linked run refused at method_id +├── pipelex-inputs/references/ # synthetic.md, user-data.md — the strategies and their worked examples, synthetic.md also the `kind: "test"` the factory's files are uploaded with; published-address.md — a method_ref target; prepare-errors.md — prepare's input and method problems, keyed on their code, the size limit's terminal branch included; each read on its condition +├── pipelex-run/references/ # by-id.md — a catalog id target, its version forms and which version ran, read at step 1; published-address.md — a method_ref target, read at step 1; failed-run.md — the failure routing, read before a failed run is routed; linked-run.md — a linked run whose method_id is unknown ├── pipelex-lab/references/ # frame.md — the questions, a candidate's shape and the brief, read at the first move with the shared fit.md; key.md — the answer key's format, read before a key is written; log.md — the log, the regression rule and the scorecard, read before the first entry -├── pipelex-catalog/references/ # python.md — which .py files a PipeFunc bundle sends, read at Save step 3; link-file.md — a save whose link write failed; conflict.md — a save refused at expected_updated_at, or a restore of a pulled version; unknown-id.md — an error at method_id, from a save, a publish or a pull; each read on its condition +├── pipelex-catalog/references/ # python.md — which .py files a PipeFunc bundle sends, read at Save step 3; link-file.md — a save whose link write failed; conflict.md — a save refused at expected_updated_at, or a restore of a pulled version; unknown-id.md — a miss or a problem at method_id, from a save, a publish or a pull, told apart by its code; each read on its condition ├── pipelex-integrate/references/ # typescript.md, python.md — detection, call-site templates, list narrowing, what the results carry; refresh.md, harness.md, signature-fallback.md, orphans.md, gate-failures.md — the branches, each read on its condition; codegen-check.mjs, codegen_check.py — the offline gates copied into TS and python-pydantic projects └── pipelex-scaffold/ # references/: initializers.md, the ecosystem initializers and the env verdict's words; uncreated-copy.md, a method-app copy `make create` has not run in; version-managers.md and github.md; each read on its condition; scripts/: commit-pristine.sh and write-env-file.sh, the initializer branch's pristine commit and env file, run by path pipelex/ # Claude prod plugin (generated, checked in) @@ -198,6 +198,6 @@ So there is nothing to enable — the bundled hook loads on its own (hooks are S ## Key dependency -The plugin imports nothing and requires no install. Validation rides on the vendored `check.mjs` bundle (wasm engine + `@pipelex/sdk` → hosted API) and, for the MCP-backed skills (`pipelex-design`, `pipelex-organize`, `pipelex-edit`, `pipelex-inputs`, `pipelex-run`, `pipelex-catalog`, `pipelex-integrate`), on the plugin-declared `pipelex-mcp` server (tools `mthds_validate` / `mthds_inputs_template`; `mthds_models`, which `pipelex-design` and `pipelex-edit` call to list the model deck and check a model reference before writing one, as the MTHDS reference's "Model references" section says; `mthds_codegen`, whose write arm — `output_dir`, relative to the workshop's working directory — writes `pipelex-integrate`'s generated trees to disk so no artifact byte passes through the model; `mthds_prepare_inputs`, which uploads `pipelex-inputs`' file-bearing values to Pipelex storage and rewrites them to `pipelex-storage://` references so a run can reach them, recording the files `pipelex-synthetic-inputs` made as the saved method's test files with `kind: "test"`; `mthds_list_files`, which `pipelex-inputs` and `pipelex-run` call, optionally, to find a file the organization already holds before asking for one, and whose `pipelex-storage://` address a run takes as it is; plus the `mthds_run` family, which runs a method only in `pipelex-run` — `pipelex-inputs` ends by offering the run and hands it over, and `pipelex-synthetic-inputs` calls it for one thing, the image generation that makes a photograph — and `mthds_list_methods` / `mthds_save_method` / `mthds_get_method` / `mthds_publish_method`, which are `pipelex-catalog`'s: the last three are **workshop-only**, the save reads, validates and stores one bundle as the method's draft in a single call, an invalid one included, and finishes by writing the `pipelex-method.json` link that makes the next save write the same method's draft, the get brings a saved method's draft or one of its published versions to disk, and the publish makes the draft the method's next version, which callers of its bare id run, and is called only on the user's request. `pipelex-design`, `pipelex-edit` and `pipelex-organize` hold `mthds_save_method` too, for the one save they end with: the linked method's draft, sending nothing from the link but its id. The save and the get refuse rather than overwrite, the publish refuses a draft that moved since it was seen, and the link file is the workshop's to write — no skill writes one. `mthds_get_method`'s **inline** arm is `pipelex-explain`'s instead, and the split is the whole of it: called with an `output_dir` it writes a pull, which is `pipelex-catalog`'s gesture, and called without one it returns the source for a skill that writes nothing — which is why a strictly read-only skill can hold this tool at all; declared in the Claude and Codex manifests, and shipped on Vibe as the `mcp/vibe-mcp.toml` entry the user appends to `~/.vibe/config.toml`). The baked declaration is the **local workshop launcher** — `npx -y @pipelex/mcp@latest` over stdio, from the `[vars.mcp_server]` block in `targets/defaults.toml` — never a hosted URL: the hosted console is a connector users add in their host's own UI (see `docs/install.md`, "Which app takes what", and `docs/decisions.md`). Credential delivery: on Claude the manifest's `userConfig` prompts for the API key / base URL at enable time (keychain-stored) and the MCP entry spawns the `launch-pipelex-mcp.sh` wrapper, which receives them as `PIPELEX_PLUGIN_*` via `${user_config.*}` substitution and promotes each to `PIPELEX_API_KEY`/`PIPELEX_BASE_URL` **only when non-empty** — the canonical credential channel (required for Claude Desktop, which carries no shell env), with the non-empty guard keeping an unfilled option from shadowing a shell-exported key; injecting `PIPELEX_*` directly instead makes an empty option surface as a config-class `Unauthorized` that hard-stops every MCP-backed skill; on Codex the manifest forwards `PIPELEX_API_KEY`/`PIPELEX_BASE_URL` by name via `env_vars` because Codex whitelist-filters MCP spawn env; on Vibe the entry carries no key, because Vibe spawns stdio servers with a minimal environment that keeps `HOME`, so the workshop reads the key `npx -y @pipelex/mcp@latest login` saved in `~/.pipelex/.env`, its fallback on every target when the host hands it none. Dev override: `make claude-local-mcp` or `make codex-local-mcp`, never an edit of `targets/defaults.toml` (`docs/development.md`, "A local build of `pipelex-mcp`"). +The plugin imports nothing and requires no install. Validation rides on the vendored `check.mjs` bundle (wasm engine + `@pipelex/sdk` → hosted API) and, for the MCP-backed skills (`pipelex-design`, `pipelex-organize`, `pipelex-edit`, `pipelex-inputs`, `pipelex-run`, `pipelex-catalog`, `pipelex-integrate`), on the plugin-declared `pipelex-mcp` server (tools `mthds_validate` / `mthds_inputs_template`; `mthds_models`, which `pipelex-design` and `pipelex-edit` call to list the model deck and check a model reference before writing one, as the MTHDS reference's "Model references" section says; `mthds_codegen`, whose write arm — `output_dir`, relative to the workshop's working directory — writes `pipelex-integrate`'s generated trees to disk so no artifact byte passes through the model; `mthds_prepare_inputs`, which uploads `pipelex-inputs`' file-bearing values to Pipelex storage and rewrites them to `pipelex-storage://` references so a run can reach them, recording the files `pipelex-synthetic-inputs` made as the saved method's test files with `kind: "test"`; `mthds_list_files`, which `pipelex-inputs` and `pipelex-run` call, optionally, to find a file the organization already holds before asking for one, and whose `pipelex-storage://` address a run takes as it is; plus the `mthds_run` family, which runs a method only in `pipelex-run` — `pipelex-inputs` ends by offering the run and hands it over, and `pipelex-synthetic-inputs` calls it for one thing, the image generation that makes a photograph — and `mthds_list_methods` / `mthds_save_method` / `mthds_get_method` / `mthds_publish_method`, which are `pipelex-catalog`'s: the last three are **workshop-only**, the save reads, validates and stores one bundle as the method's draft in a single call, an invalid one included, and finishes by writing the `pipelex-method.json` link that makes the next save write the same method's draft, the get brings a saved method's draft or one of its published versions to disk, and the publish makes the draft the method's next version, which callers of its bare id run, and is called only on the user's request. `pipelex-design`, `pipelex-edit` and `pipelex-organize` hold `mthds_save_method` too, for the one save they end with: the linked method's draft, sending nothing from the link but its id. The save and the get refuse rather than overwrite, the publish refuses a draft that moved since it was seen, and the link file is the workshop's to write — no skill writes one. `mthds_get_method`'s **inline** arm is `pipelex-explain`'s instead, and the split is the whole of it: called with an `output_dir` it writes a pull, which is `pipelex-catalog`'s gesture, and called without one it returns the source for a skill that writes nothing — which is why a strictly read-only skill can hold this tool at all; declared in the Claude and Codex manifests, and shipped on Vibe as the `mcp/vibe-mcp.toml` entry the user appends to `~/.vibe/config.toml`). The baked declaration is the **local workshop launcher** — `npx -y @pipelex/mcp@latest` over stdio, from the `[vars.mcp_server]` block in `targets/defaults.toml` — never a hosted URL: the hosted console is a connector users add in their host's own UI (see `docs/install.md`, "Which app takes what", and `docs/decisions.md`). Credential delivery: on Claude the manifest's `userConfig` prompts for the API key / base URL at enable time (keychain-stored) and the MCP entry spawns the `launch-pipelex-mcp.sh` wrapper, which receives them as `PIPELEX_PLUGIN_*` via `${user_config.*}` substitution and promotes each to `PIPELEX_API_KEY`/`PIPELEX_BASE_URL` **only when non-empty** — the canonical credential channel (required for Claude Desktop, which carries no shell env), with the non-empty guard keeping an unfilled option from shadowing a shell-exported key; injecting `PIPELEX_*` directly instead makes an empty option surface as a refused credential, a problem in the `account` domain that hard-stops every MCP-backed skill; on Codex the manifest forwards `PIPELEX_API_KEY`/`PIPELEX_BASE_URL` by name via `env_vars` because Codex whitelist-filters MCP spawn env; on Vibe the entry carries no key, because Vibe spawns stdio servers with a minimal environment that keeps `HOME`, so the workshop reads the key `npx -y @pipelex/mcp@latest login` saved in `~/.pipelex/.env`, its fallback on every target when the host hands it none. Dev override: `make claude-local-mcp` or `make codex-local-mcp`, never an edit of `targets/defaults.toml` (`docs/development.md`, "A local build of `pipelex-mcp`"). **`pipelex-synthetic-inputs` depends on none of that for code-rendered files.** Everything but a photograph is MCP-free — no tool, no key, no Pipelex service — and a photograph alone needs the workshop, whose absence stops that one file and nothing else. `pipelex-scaffold` is the other skill that declares no MCP tool: git, the method-app family's initializer and `make serve`, the ecosystem's initializers and its own two scripts are all it uses, and it leaves a method app running and hands every other project it creates to `pipelex-integrate`. For code-rendered files, the only dependency is a Python the skill can reach: `uv` with ephemeral `--with` packages on the normal rung, and a venv it creates itself under `${XDG_CACHE_HOME:-$HOME/.cache}/pipelex-plugins/synth-venv` when `uv` is absent. Swapping the runner line is the *only* difference between the two rungs, and `tests/recipes` proves it by running real recipes through both. When neither rung is reachable the skill stops with the exact missing piece and, called from `pipelex-inputs`, returns no path so that one input is left unfilled rather than aborting the flow. Keep it and `pipelex-scaffold` out of the `MCP_SKILLS` tuple in `tests/unit/test_gen_skill_docs.py`, and `pipelex-explain` and `pipelex-lab` with them — the lab frames and writes keys without the workshop and stops only before its loop. For explain, the workshop is **optional** — it adds a verdict line to a bundle on disk, reads a saved method's source in full through `mthds_get_method`'s inline arm, and is the only way to reach a catalog id or a published address at all, but its absence never stops the skill from explaining local source. A workshop older than the release that brought `mthds_get_method` answers the other tools without it, so there a catalog id falls back to contract level, which is a narrower explanation and not a stop. The tuple asserts a hard stop, which is a different contract. diff --git a/docs/build-targets.md b/docs/build-targets.md index 00782ae4..c8cada88 100644 --- a/docs/build-targets.md +++ b/docs/build-targets.md @@ -186,7 +186,7 @@ A file git ignores is left out of the comparison, as it is left out of the pruni - **Leaked templates** anywhere in a target's directory, and under the root's `skills/`, `hooks/` and `mcp/`. - **An in-repo target on an outside-only platform**, `agent-skills`, which the build refuses as well ("Outside targets" below). -One unit test reads the generated skills for a vocabulary rather than a shape: `tests/unit/test_skill_error_fields.py` fails when any file a target ships under `skills/`, a reference or a script included, names a field of the runtime's error report that the MTHDS problem document replaced (`error_type`, `error_domain`, `error_category`, `user_action`, `caller_facing_message`): pipelex no longer writes them, and the workshop, which still relays them on a failed run's `failure` object while the hosted plane runs an older pipelex, drops them when it moves to the problem document. The error fields the skills do name, a verdict's `validation_errors[]`, an error's `class`, `retryable`, `location`, `hint` and `kind`, and a failed run's `failure_message`, are the workshop's own contract, which the skills follow as it stands and which moves to the problem document with the workshop itself. +One unit test reads the generated skills for a vocabulary rather than a shape: `tests/unit/test_skill_error_fields.py` fails when any file a target ships under `skills/`, a reference or a script included, names an error field nobody sends any more. Two vocabularies are retired. The first is the runtime's error report, which the MTHDS problem document replaced (`error_type`, `error_domain`, `error_category`, `user_action`, `caller_facing_message`). The second is the workshop's own error contract before it moved to the problem document: a no-verdict error's `class` (`input_domain`, `config`, `runtime`), its `retryable` flag, its `hint` and its `kind` tag (`kind: "auth"`, `kind: "role"`), a failed run's `failure_message` and `failure` report, and the platform's old codes `method_not_published` and `method_version_not_found`. The workshop now answers a call that produced no verdict with `status: "error"` and one `problem`, the caller's view of the problem document, whose `code`, `domain`, `retry`, `next_step`, `params`, structured `location`, `errors` items and `request_id` are what the skills branch on and relay; a verdict's faults ride `errors[]`, one problem item each, and its warnings are problem items too; and a failed run carries its own problem as `run_error`, or `error` on `mthds_run_status`. `validation_errors` is the one name of the old contract the workshop keeps, on `mthds_save_method` and `mthds_publish_method`, whose verdict's faults it still carries under that name as problem items, so the test lets `pipelex-catalog`, the skill that reads those two tools' verdicts, name it and refuses it everywhere else. ## Per-target skill overlays @@ -371,9 +371,9 @@ So the bump procedure is: edit `[vars.floors]`, run `make build`, run `make chec | Partial | What it carries | Parameters the including template sets | | --- | --- | --- | | `frontmatter.md.j2` | the YAML frontmatter fields shared by every skill (Claude's `allowed-tools`) | `skill_tools` (the harness-native tools the skill pre-approves; defaults to the writing set) | -| `mcp-requirements.md.j2` | the two stops an MCP-backed skill opens with — an absent tool, a `config`-class error surfaced verbatim — each pointing at `shared/credentials.md` for what to tell the user | `mcp_absent_lead` (`the tool is`, `the tools are`, `a tool is`), `mcp_absent_suffix`, `mcp_config_parenthetical`, `mcp_config_suffix`, `mcp_requirements_extra` (a bullet appended after the two stops) | +| `mcp-requirements.md.j2` | the two stops an MCP-backed skill opens with — an absent tool, and a problem in the `account` domain or `client.unreachable`, its `next_step` relayed verbatim — each pointing at `shared/credentials.md` for what to tell the user | `mcp_absent_lead` (`the tool is`, `the tools are`, `a tool is`), `mcp_absent_suffix`, `mcp_config_parenthetical`, `mcp_config_suffix`, `mcp_requirements_extra` (a bullet appended after the two stops) | | `validate-call.md.j2` | how a local bundle is handed to the workshop, in a folder form and a listing form. The folder form, the default, passes the bundle directory as `method_dir`, which the workshop reads under its own membership rule, sending the `.mthds` files and the template files their `PipeDocGen` steps name and listing them in `files_sent`, with the workshop's refusal of a folder outside its working directory and the relaunch that cures it, the inline fallback with the files it sends, the `.mthds` files outside `runs/` with the root file first, which is one for a bundle with no template file, a templated bundle out of reach being a stop, and the pointer to the language reference's fallback for a workshop older than the folder form. The listing form is the convention the folder replaced: which files (every `.mthds` file beneath the bundle directory except `runs/`, and every template file a `PipeDocGen` step names), the path form of `files`, the root `.mthds` file first, the same refusal and inline fallback; the catalog's save uses it, and so does the language reference's fallback, which includes it whole. `pipelex-integrate` takes the folder form, since its call site sends the bundle directory as the method's tree under the same standard's lister, so `files_sent` is the set it records and its gates hash, and it replaces both fallbacks with a stop, since neither sends that tree | `validate_call_folder` (`false` for the listing form: in `pipelex-catalog`, since `mthds_save_method` takes no folder, and in `writing-mthds.md.j2`'s fallback for an older workshop); `validate_call_tree_only` (`true` in `pipelex-integrate` alone, whose folder form names no inline or older-workshop fallback and makes a bundle out of reach, or a workshop without `method_dir`, a stop); the rest apply to the listing form alone: `validate_call_templates` (`false` in `pipelex-catalog` alone, since the catalog stores no template file and the save refuses one); `validate_call_root_first` (`false` in `pipelex-catalog` alone, whose save step states the order with its own reason); `validate_call_inline` (what is said of the inline form after its shape, that it is the fallback for a bundle with no template file by default; set by `pipelex-catalog` alone, since a save sent inline is left unlinked) | -| `validate-warnings.md.j2` | that a valid verdict's `warnings` are reported, with a pointer to the language reference's "Template files" section before acting on a `template_check_warning` — for design, edit, explain and run, the skills that report a verdict | none | +| `validate-warnings.md.j2` | that a valid verdict's `warnings` are reported, with a pointer to the language reference's "Template files" section before acting on a `pipelex.docgen.template_warning` — for design, edit, explain and run, the skills that report a verdict | none | | `stale-types-notice.md.j2` | the notice that a bundle change may have outdated a generated tree, in one wording for its three call sites | none | | `saved-copy-notice.md.j2` | the closing step that saves the change as the linked method's draft, sending nothing from the link but its id and no template file, saying so through `template-not-stored.md.j2`, leaving a refusal to `/pipelex-catalog` and never publishing | none | | `template-not-stored.md.j2` | the one sentence a save says of a bundle whose steps name a template file: the catalog stores none yet, so the draft reports it missing and runs only from its directory — for the catalog's save and the saved-copy notice | none | diff --git a/docs/decisions.md b/docs/decisions.md index fa26a9f4..db7a56c1 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -920,6 +920,18 @@ A runner speaking the MTHDS problem document carries an invalid verdict's faults - **The bundle is rebuilt on the `@pipelex/sdk` 0.53.0 release, the first whose hook reads the items.** Its banner names 0.53.0 and that release's commit, and `@pipelex/tools-wasm` stays at 0.6.0. The bundle was first re-vendored from the SDK branch that carried the reading, ahead of the release, which let the strict expected failure go early; `make check-hook-fresh` compares what lies below the banner with a rebuild on the SDK's `dev`, and that body holds the SDK's version string and every client module the bundle inlines, so the release gate held the bundle to a second re-vendor once the SDK released. The hook reads the items through the SDK's own reader of a verdict's problem items, `readProblemItems`, the one every verdict the SDK reads goes through. Nothing else the hook uses moved since the bundle built on `@pipelex/sdk` 0.48.1: its lint, its format and the request its validate stage sends are the same, and only its `User-Agent` names the new version. The bundle also carries the client changes the SDK made meanwhile, which the hook never calls, among them every error reshaped as a problem document; the validate stage catches whatever its call throws and is skipped, as before, so none of them reaches the agent. - **The reason names each item, and `validation_errors[]` is no longer read.** Each item is a line with its code, its sentence and its location, in the `mthds` package's wording, with its suggested fix beneath it, and an entry the bundle cannot read is skipped or trimmed rather than failing the block. A server of the older shape that also ignores `render` now gets the verdict's message alone, which is accepted: the hosted plane, the hook's default, speaks the problem document, and nothing here keeps a compatibility path. The strict expected failure is gone, and the test passes outright. +## The skills read the workshop's problem document (2026-10-24) + +The workshop moves its errors to the MTHDS problem document (the sprint member `L-261019-81eeeb` in the workspace ledger, on `pipelex-mcp`'s `feature/Workshop-problem-errors`), and this plugin's item `L-261017-1b4ac0` moves the skills with it. A call that produced no verdict now answers `status: "error"` with one `problem`, the caller's view of the problem document: a `code` from the protocol's registry or the platform's, a `domain` saying whose the fix is (`input`, `method`, `account`, `operator`, `runtime`), a `retry` verdict (`no`, `yes`, `outcome_unknown`), a `next_step` with its kind, `params`, a structured `location`, `errors` items, the `request_id`, and the workshop's own sentence as `message`. A verdict's faults ride `errors[]`, one problem item each, and so do its `warnings`; a failed run carries the problem it ended with as `run_error`, or `error` on the status tool. The old contract's `class` (`input_domain`, `config`, `runtime`), `retryable`, `hint`, `kind` tag, free-string `location`, a verdict's `validation_errors[]` and a failed run's `failure` and `failure_message` are gone, except that `mthds_save_method` and `mthds_publish_method` keep `validation_errors` as the name of their verdict's faults, now problem items. The field names in the earlier entries of this file are the contract they were written under; this entry says what each became. + +- **The skills branch on `code`, then `domain` and `retry`, never on wording.** The shared requirements' second stop, the old `config` class, is now a problem in the `account` domain, which covers a missing, refused or expired key, a role and the organization's credit or plan, or `client.unreachable`, an API the workshop could not reach; the skill relays its `next_step` verbatim and reads the credentials reference when the code is one of the three `auth` credential codes. The old `input_domain` stop rows became `domain: "input"`, fixed in the call, and the old `runtime` row became a retry once when `retry` is `"yes"` and a report otherwise. `auth.forbidden` is the one account problem a login cannot cure, so the credentials reference says so, rather than sending the user to the login for a role. +- **The references that told faults apart by their location now tell them apart by their code.** The catalog's unknown-id reference reads `pipelex.catalog.not_found` (of a method or of a version) apart from `client.target_exists` (a link naming another method), `client.argument_invalid` with `version_suffix`, and `method.package_invalid` with `empty_tree`, all of which a location alone confused. The linked run's reference reads the unknown linkage id by `pipelex.catalog.not_found`. `pipelex-inputs`' prepare reference is keyed on the code too: the size limit is `client.argument_invalid` with `upload_too_large`, an unreadable local path `input.file_unreadable`, and an unresolved closure `method.invalid`, `request.pipe_not_found` or `request.pipe_ambiguous`. +- **A failed run is reported from its problem.** `pipelex-run`'s step 8 gives `run_error` verbatim, and its failed-run reference names where the problem rides on each run tool, keeps the support line the workshop's summary closes with, and reads the `domain` beside the wording before routing. The lab logs a failure by its code and title, and the synthetic-inputs photograph reports it as the run does. +- **Prepare by address never meets the execution-locus gate.** `mthds_prepare_inputs` reads an address's signature from `POST /v1/pipe-io`, which loads the package's `.mthds` files alone, so the published-address reference's branch saying that a package shipping Python is refused there, wearing the credential's wording, is gone: a problem in the `account` domain on prepare is the credential and only the credential, and the deployment's refusal of Python, `pipelex.deployment.custom_code_requires_sandbox`, meets the run. This settles what `L-260923-4ce273` reported. +- **The guard test refuses both retired vocabularies.** `tests/unit/test_skill_error_fields.py` refused the runtime's error report's fields; it now refuses the workshop's old ones too, and lets `validation_errors` through only in `pipelex-catalog`, whose two tools still send it, as `docs/build-targets.md` describes. +- **The ceiling paid for it with wording.** The codes are longer than the classes they replace, so each stop row was rewritten rather than extended: integrate's branch for a file the codegen does not own names the code instead of quoting the message, and the run skill's linked-run row names the code instead of a location. +- **A refusal of `kind` is answered by the fallback, never by a stop.** On a call that passed `kind: "test"`, the platform refuses a test upload for the caller's role as `auth.forbidden`, a problem in the `account` domain, and a method it no longer holds or is erasing as `client.argument_invalid` naming `method_id`, with no location, beside the workshop's own refusals naming `kind` and its `version_suffix` at `method_id`. Preparing again without `kind` cures each of them, so `pipelex-inputs` exempts `auth.forbidden` on such a call from the shared account stop in its own requirement for `mthds_prepare_inputs`, not in the shared partial's suffix, which the template call renders too, and gives these refusals a stop row of their own above the prepare-errors row, whose condition now excludes a refusal of `kind` rather than a location. Any other refusal naming `method_id`, such as `not_a_catalog_id`, stays a fault of the target. The ceiling paid with wording again: the pointers' link texts name the file alone, and a few clauses that gave a reason or repeated a neighbouring sentence were cut. + ## License & distribution **Elastic License 2.0** since 2026-09-30, Apache 2.0 before. Two exceptions. Code the skills copy or write into a user's project is granted under MIT-0, stated in the README's License section and as an SPDX line in the two copied gates, because it lands in the user's own repository, which they may publish, and ELv2's terms would otherwise travel with it. The vendored `check.mjs` is MIT code from other Pipelex packages and a fork of Taplo, and ships with its notice beside it. The repo is public (required for easy marketplace install). Versions start at **0.1.0** (plugin and marketplace). GitHub home assumed `Pipelex/pipelex-plugins` — confirm at first push. diff --git a/docs/install.md b/docs/install.md index 83e455b4..8c14ddb1 100644 --- a/docs/install.md +++ b/docs/install.md @@ -172,6 +172,6 @@ A chatbot takes the Pipelex MCP rather than the plugin. Add it in the chatbot's https://mcp.pipelex.com/mcp ``` -The sign-in is OAuth, and the chatbot drives it, including the choice of the organization you work in. The Pipelex MCP holds no key of its own and has no keyless mode: every call runs on your signed-in session, so the methods you see and the runs you spend are your own. When a session expires or is revoked, calls come back as a `config` no-verdict telling you to reconnect and sign in again. +The sign-in is OAuth, and the chatbot drives it, including the choice of the organization you work in. The Pipelex MCP holds no key of its own and has no keyless mode: every call runs on your signed-in session, so the methods you see and the runs you spend are your own. When a session expires or is revoked, calls come back with an error telling you to reconnect and sign in again. > **Upgrading from an `?api_key=` address.** The Pipelex MCP stopped taking an API key in its 0.12.0 release. An entry still registered with `?api_key=plx_sk_...` in its address, or with an `Authorization: Bearer plx_sk_...` header, no longer connects at all: remove it, add it again by the plain address above, and revoke in your console at [app.pipelex.com](https://app.pipelex.com) the key it carried, since a key that sat in an address may have reached browser history, copied links and proxy logs. ChatGPT keeps the configuration it read when the entry was added, so adding it again is the only way through there. diff --git a/pipelex-codex/skills/pipelex-catalog/SKILL.md b/pipelex-codex/skills/pipelex-catalog/SKILL.md index adae4fde..cd542d74 100644 --- a/pipelex-codex/skills/pipelex-catalog/SKILL.md +++ b/pipelex-codex/skills/pipelex-catalog/SKILL.md @@ -11,7 +11,7 @@ Every gesture between a bundle directory and the organization's catalog: [list a - **`mthds_list_methods`**, **`mthds_save_method`**, **`mthds_publish_method`** and **`mthds_get_method`** are required, with no fallback. - **If the catalog tools are absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Codex. Never report a method id, a name, a version, or a method as saved or published when the answer did not come from these tools. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. ## Guards @@ -57,10 +57,10 @@ The target is a bundle directory. | a templated bundle answers `is_valid: false`, its template *not supplied with its bundle* | expected, as step 4 says: the draft runs only from its directory and cannot be published to run by id. **Never route it to editing** | | a save or a publish answers `is_valid: false` | a **produced verdict**, not an error: the save stored the draft anyway, and the publish published nothing. Report `validation_errors[]`; route a contract-preserving fix to `/pipelex-edit`, a structural one to `/pipelex-design` | | the bundle is valid with pending signatures | A **valid bundle with pending signatures is saved**, as a draft: say plainly that the method does not run yet, and which signatures are still open | -| `input_domain` at `expected_updated_at`: the draft moved since this directory synced, or it holds a pulled version | nothing was written. Read [conflict.md](references/conflict.md) before replying: unless it finds this session's own save, give the user the timestamps and the ways forward it describes. **Never choose between them.** | -| `input_domain` at `expected_draft_updated_at` | nothing was published: the draft moved since it was seen. Publish only once the user has seen it, saved or pulled, **never under the token the refusal names** | -| `input_domain` at `method_id` | read [unknown-id.md](references/unknown-id.md) before concluding anything: several faults land there. A dead link is removed only on the user's yes, the one thing this skill ever takes off disk | -| a create fails on a timeout or a transport fault | **does not retry.** A create carries no idempotency key yet, so a retry mints a second method: list the catalog first and see whether the first one landed | +| a problem at `expected_updated_at`: the draft moved since this directory synced, or it holds a pulled version | nothing was written. Read [conflict.md](references/conflict.md) before replying: unless it finds this session's own save, give the user the timestamps and the ways forward it describes. **Never choose between them.** | +| a problem at `expected_draft_updated_at` | nothing was published: the draft moved since it was seen. Publish only once the user has seen it, saved or pulled, **never under the token the refusal names** | +| `pipelex.catalog.not_found`, or a problem at `method_id` | read [unknown-id.md](references/unknown-id.md) before concluding anything: its `code` tells the faults apart. A dead link is removed only on the user's yes, the one thing this skill ever takes off disk | +| a create answers `client.outcome_unknown` | **does not retry.** A retry mints a second method: list the catalog first and see whether the first one landed | | the pull's directory holds a bundle of its own, or a link naming another method | somebody else's work: pull into another directory | | the pull's directory is linked to this method, files identical | only the link's `synced_updated_at` was refreshed: say the directory was already up to date | | linked, files differ, the saved method has **not** moved | the difference is local work this directory never saved: offer to [save](#save) it, or to pull into a new sibling directory to compare | @@ -72,4 +72,4 @@ The target is a bundle directory. - [python.md](references/python.md): the bundle holds a `PipeFunc`, before choosing `python`. - [link-file.md](references/link-file.md): a save's `link_file` came back `written: false`. - [conflict.md](references/conflict.md): a save refused at `expected_updated_at`, or a restore. -- [unknown-id.md](references/unknown-id.md): an `input_domain` error at `method_id`. +- [unknown-id.md](references/unknown-id.md): a miss, or a problem at `method_id`. diff --git a/pipelex-codex/skills/pipelex-catalog/references/conflict.md b/pipelex-codex/skills/pipelex-catalog/references/conflict.md index fb2a1c31..47aed0e5 100644 --- a/pipelex-codex/skills/pipelex-catalog/references/conflict.md +++ b/pipelex-codex/skills/pipelex-catalog/references/conflict.md @@ -1,6 +1,6 @@ # When a save is refused at `expected_updated_at`, or a version is restored -Read this when `mthds_save_method` answers an `input_domain` error at `expected_updated_at`, or before saving a directory that holds a pulled version because the user asked to restore it, before replying to the user. A refusal writes nothing, not the draft and not the link. A conflict names the draft's current `updated_at` and the token the save was sent under; a save refused because the directory holds a pulled version names the token a restore takes. Only the draft is at stake: published versions never change, and nothing below publishes. +Read this when `mthds_save_method` answers a problem at `expected_updated_at`, or before saving a directory that holds a pulled version because the user asked to restore it, before replying to the user. A refusal writes nothing, not the draft and not the link. A conflict is `pipelex.catalog.update_conflict`, whose `message` names the draft's current `updated_at` and the token the save was sent under; a save refused because the directory holds a pulled version is `client.argument_invalid` with `params.reason` `version_pulled`, whose `message` names the token a restore takes. Only the draft is at stake: published versions never change, and nothing below publishes. **First, does the directory hold a pulled version?** When `pipelex-method.json` records a `synced_version`, or the refusal says the directory holds one, the files here are version n, pulled to read or to start over from, perhaps edited since, and saving them replaces the draft with them: a restore. Unless the user asked for it, say so and give the two ways forward: pull the draft back into this directory to go on working on the draft, or restore, which makes these files, edits included, the draft. The pull writes over the version's untouched files freely, since the catalog stores them, and refuses a file edited since the version pull: those edits survive only a restore or a copy the user moves aside first, so never answer that refusal with `overwrite: true` without saying the edits are lost. A restore, made only on the user's request or an explicit yes, is the same call with `expected_updated_at` set to the `updated_at` the version pull reported, which the link records as `synced_updated_at` and the refusal names too, and `python` as the version's `.py` files, or `[]` when it has none, since an omitted `python` keeps the draft's. That token is the draft as the pull found it, so a draft saved since then refuses the restore: that refusal is a conflict, answered as the last paragraph and its two ways forward say, and saving over it is this restore sent with the draft's current `updated_at`, on the user's yes once they have seen both timestamps. Never take the draft's current `updated_at` for a restore before that refusal, from a pull or from anywhere else: it would restore over a draft nobody here has seen. A restore publishes nothing; a publish of the restored draft is a request of its own. diff --git a/pipelex-codex/skills/pipelex-catalog/references/unknown-id.md b/pipelex-codex/skills/pipelex-catalog/references/unknown-id.md index 2dd255c2..80112b26 100644 --- a/pipelex-codex/skills/pipelex-catalog/references/unknown-id.md +++ b/pipelex-codex/skills/pipelex-catalog/references/unknown-id.md @@ -1,15 +1,19 @@ -# An error at `method_id` +# A miss, or a problem at `method_id` -Read this when `mthds_save_method`, `mthds_publish_method` or a pull's `mthds_get_method` answers an `input_domain` error at `method_id`, before concluding anything about the directory's link. The skill's guard on the link holds throughout: it is removed only on the user's yes. +Read this when `mthds_save_method`, `mthds_publish_method` or a pull's `mthds_get_method` answers `pipelex.catalog.not_found`, or another problem located at `method_id`, before concluding anything about the directory's link. The skill's guard on the link holds throughout: it is removed only on the user's yes. -An unknown `method_id` comes back at that location, and so do several other faults: a payload the platform rejected, an organization-context failure, and the workshop's own refusal when this directory's link names a *different* method from the id being saved. **The location alone never tells them apart**, so read the message and the hint before doing anything: only the not-found answer names `pipelex-method.json` and the `api_host` and explains that the catalog is org-scoped, so a method from another organization reads exactly like a miss. Anything else is a different fault: the link is not dead, it stays where it is, and the fix is to the call. +Several faults land on the same id, and **the problem's `code` tells them apart**, never its location or its wording. Only `pipelex.catalog.not_found` whose `params.resource` is `method` is a miss: the catalog is org-scoped, so a method from another organization reads exactly like one. Anything else is a different fault, the link is not dead, it stays where it is, and the fix is to the call: -**A version suffix is refused there too, and is not a miss.** A save and a publish take the bare id, since both act on the draft, so `mt_…@` is refused before anything is sent: call again with the bare id, and to publish an old version's content again, pull that version, restore it as the draft and publish that. A pull of a version the method never had names the versions it has: offer one of those, or the draft. +- `client.target_exists` at `method_id` is the workshop's own refusal when this directory's link names a *different* method from the id being saved. Its `message` names both and what to pass instead. +- `client.argument_invalid` at `method_id` is a call the workshop refused before sending it, its `params.reason` saying why. **A version suffix is refused there, as `version_suffix`, and is not a miss.** A save and a publish take the bare id, since both act on the draft, so `mt_…@` is refused before anything is sent: call again with the bare id, and to publish an old version's content again, pull that version, restore it as the draft and publish that. +- `pipelex.catalog.not_found` whose `params.resource` is `version` is a pull of a version the method never had. Its `message` names the versions it has: offer one of those, or the draft. +- `method.package_invalid` with `params.reason` `empty_tree` is a pull of a method whose stored source holds no file yet. It is not a miss: relay it as the pull's report step says. +- Any other code, such as a payload the platform rejected or a failure of the organization's context, is relayed with its `detail` and `next_step`. -**A save's miss is checked against a read first.** When a save answers that the id is not visible, call `mthds_get_method` on the same bare id without `output_dir`: when it reads the method, the id is alive and this platform has no draft save yet, a platform older than drafts. Say so and stop; the link stays and nothing here creates a method. +**A save's miss is checked against a read first.** When a save answers `pipelex.catalog.not_found`, call `mthds_get_method` on the same bare id without `output_dir`: when it reads the method, the id is alive and this platform has no draft save yet, a platform older than drafts. Say so and stop; the link stays and nothing here creates a method. -When the hint does say the id is not visible, and a read does not find it either, report it **with the `api_host` the link file records** — that is what makes it diagnosable: the link was made against another plane, or with another organization's key. +When a read does not find it either, report the miss **with the `api_host` the link file records** — that is what makes it diagnosable: the link was made against another plane, or with another organization's key. Then offer to save the directory as a **new** method. That needs the stale link gone first: the workshop refuses a create into a directory another link claims, rather than minting a duplicate nobody can delete. So ask, and on a yes remove `pipelex-method.json` and run the create, which writes a fresh link. -**A pull or a publish has no link to judge.** When the error came from `mthds_get_method` or `mthds_publish_method`, nothing was written or published and nothing on disk is touched. An empty stored source answers at the same location and is not a miss: relay it as the pull's report step says. Otherwise relay the answer and its hint, and when the hint says the id is not visible, say that a method saved from another organization, or on another plane, reads exactly like a miss, and offer to find the method by name, as the skill's "List and find" says. +**A pull or a publish has no link to judge.** When the problem came from `mthds_get_method` or `mthds_publish_method`, nothing was written or published and nothing on disk is touched. Relay its `detail` and `next_step`, and on a miss say that a method saved from another organization, or on another plane, reads exactly like one, and offer to find the method by name, as the skill's "List and find" says. diff --git a/pipelex-codex/skills/pipelex-design/SKILL.md b/pipelex-codex/skills/pipelex-design/SKILL.md index 6b598275..6e2253da 100644 --- a/pipelex-codex/skills/pipelex-design/SKILL.md +++ b/pipelex-codex/skills/pipelex-design/SKILL.md @@ -11,7 +11,7 @@ Design a `.mthds` method **contract-first**, directly or stepwise (step 3). A st - **`mthds_validate`** and **`mthds_inputs_template`** are required: this skill never guesses at validity. - **If the tools are absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Codex. Do not write `.mthds` files without validation available. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never silently skip validation. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never silently skip validation. ## Guards @@ -52,7 +52,7 @@ Design the whole graph in memory, then write `main.mthds` in the bundle home, to Call `mthds_validate`. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. -Branch on the **structured verdict**, never on transport: `is_valid: true` is complete with `is_runnable: true` and nothing pending, and otherwise a scaffold whose backlog is the summary's `## Pending signatures`; on `is_valid: false`, fix from `validation_errors[]` and the summary's locators, then re-validate. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `template_check_warning`. +Branch on the **structured verdict**, never on transport: `is_valid: true` is complete with `is_runnable: true` and nothing pending, and otherwise a scaffold whose backlog is the summary's `## Pending signatures`; on `is_valid: false`, fix from `errors[]`, then re-validate. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `pipelex.docgen.template_warning`. ### 6. The runnable gate and delivery @@ -65,7 +65,7 @@ For a completed method, validate once more and confirm **`is_valid: true`, `is_r 5. **Hand off**: `/pipelex-inputs` prepares the user's files, or test files with planted facts, then `/pipelex-run` runs the method, and `/pipelex-lab` writes answer keys and scores the runs; `/pipelex-catalog` saves it under an `mt_…` id; `/pipelex-integrate` wires it into a codebase (a `package.json` or a `pyproject.toml`), and with neither, `/pipelex-scaffold` creates an app around it. 6. Search the whole project for `sources.json` files carrying `"generator": "pipelex-integrate"` — `grep -rl '"pipelex-integrate"' --include=sources.json .` — which sit beside each generated tree, never beside the bundle. Keep each one whose `sources` name a `.mthds` file this change rewrote, moved or removed, or whose `templates` name a template file it changed, **or whose `bundle_dir` holds a `.mthds` file this change created** — a new file is in no `sources` map, yet the call site loads every `.mthds` file under that directory. For each, say the generated types in that directory are now stale and offer `/pipelex-integrate` to refresh them: it regenerates in place and touches the call site only if the types no longer fit it. -**Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a `config`-class error included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. +**Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a problem in the `account` domain included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. ## Re-entry @@ -77,8 +77,8 @@ For a completed method, validate once more and confirm **`is_valid: true`, `is_r | Condition | Do this | |---|---| -| `status: "error"`, class `input_domain` | fix the call | -| `status: "error"`, class `runtime` | report it, and retry once before stopping | +| `status: "error"`, `domain: "input"` | fix the call | +| any other `status: "error"` | report it, after one retry when its `retry` is `"yes"` | | validation fails twice on the same construct, or the client contract itself looks wrong | pause and show the user | ## References diff --git a/pipelex-codex/skills/pipelex-design/references/stepwise.md b/pipelex-codex/skills/pipelex-design/references/stepwise.md index 9604046c..b604c77a 100644 --- a/pipelex-codex/skills/pipelex-design/references/stepwise.md +++ b/pipelex-codex/skills/pipelex-design/references/stepwise.md @@ -48,7 +48,7 @@ Given pending signature `S` with frozen `inputs`, `output`, `description`, and ` The new file bounds the ordinary fix: - **Contract mismatch:** conform the definition to the frozen header. If the header itself is wrong, that is a propagating contract change; pause and revise the parent region deliberately rather than silently changing the header. -- **Other semantic errors:** use `validation_errors[]`, the Markdown locators, and the relevant section of the authoring reference; fix the added file and re-validate. +- **Other semantic errors:** use the verdict's `errors[]`, each item's `code`, `detail` and `location`, and the relevant section of the authoring reference; fix the added file and re-validate. ## Stopping early diff --git a/pipelex-codex/skills/pipelex-edit/SKILL.md b/pipelex-codex/skills/pipelex-edit/SKILL.md index 182c7c91..90a981f3 100644 --- a/pipelex-codex/skills/pipelex-edit/SKILL.md +++ b/pipelex-codex/skills/pipelex-edit/SKILL.md @@ -14,7 +14,7 @@ Modify an existing MTHDS method bundle. There are two classes of change; this sk - **`mthds_validate`** is required: it proves every edit. **Never declare an edit done on the hook's silence alone**: its semantic stage is skipped without an API key. - **If the tool is absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Codex. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. - **`mthds_inputs_template`** is needed only by Step 6, when the edit could have touched the input template. **`mthds_models`** serves a model change in Step 4, and its absence is no stop: the model references say what to do without it. ## Mode Selection @@ -46,7 +46,7 @@ Check the requested change against the scope split at the top. Structural or con Validate the whole bundle **before editing**: call `mthds_validate` on the bundle directory, and branch on the structured verdict, never on transport. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. - `is_valid: true` → record whether it is runnable or a scaffold (non-empty `pending_signatures`). That same state must hold after your edits. -- `is_valid: false` → the bundle is broken **before** your change: surface the `validation_errors[]` and the Markdown summary, and offer to repair first. **Never edit on a broken baseline.** +- `is_valid: false` → the bundle is broken **before** your change: surface the `errors[]` and the Markdown summary, and offer to repair first. **Never edit on a broken baseline.** ### Step 4: Apply the edits @@ -60,7 +60,7 @@ Before editing a construct you have not touched recently, read [the MTHDS refere ### Step 5: Re-validate -Same whole-bundle `mthds_validate` call as Step 3. The bar is the **baseline verdict restored**: `is_valid: true`, and the runnable or scaffold state unchanged (a renamed pending signature renames its backlog entry; nothing else in the pending set moves). **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `template_check_warning`. On `is_valid: false` the failure is in your edit: use the summary's locators, fix, re-validate. On `status: "error"` the edit is applied but **unproven** — never report it as done: tell the user it is on disk but could not be validated, and offer to restore the pre-edit content you still hold from Step 1, or to retry once the server is reachable again. +Same whole-bundle `mthds_validate` call as Step 3. The bar is the **baseline verdict restored**: `is_valid: true`, and the runnable or scaffold state unchanged (a renamed pending signature renames its backlog entry; nothing else in the pending set moves). **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `pipelex.docgen.template_warning`. On `is_valid: false` the failure is in your edit: use the summary's locators, fix, re-validate. On `status: "error"` the edit is applied but **unproven** — never report it as done: tell the user it is on disk but could not be validated, and offer to restore the pre-edit content you still hold from Step 1, or to retry once the server is reachable again. ### Step 6: Inputs refresh check @@ -72,14 +72,14 @@ State what changed (files and constructs), give the verdict line from the summar **Generated types may now be stale.** Search the whole project for `sources.json` files carrying `"generator": "pipelex-integrate"` — `grep -rl '"pipelex-integrate"' --include=sources.json .` — which sit beside each generated tree, never beside the bundle. Keep each one whose `sources` name a `.mthds` file this change rewrote, moved or removed, or whose `templates` name a template file it changed, **or whose `bundle_dir` holds a `.mthds` file this change created** — a new file is in no `sources` map, yet the call site loads every `.mthds` file under that directory. For each, say the generated types in that directory are now stale and offer `/pipelex-integrate` to refresh them: it regenerates in place and touches the call site only if the types no longer fit it. -**Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a `config`-class error included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. +**Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a problem in the `account` domain included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. ## Stops | Condition | Do this | |---|---| -| `status: "error"`, class `input_domain` | fix the call | -| `status: "error"`, class `runtime` | report it, and retry once before stopping | +| `status: "error"`, `domain: "input"` | fix the call | +| any other `status: "error"` | report it, after one retry when its `retry` is `"yes"` | | the same construct fails twice after your edit | pause and show the user instead of thrashing | ## References diff --git a/pipelex-codex/skills/pipelex-explain/SKILL.md b/pipelex-codex/skills/pipelex-explain/SKILL.md index dbdb549a..14c6f7be 100644 --- a/pipelex-codex/skills/pipelex-explain/SKILL.md +++ b/pipelex-codex/skills/pipelex-explain/SKILL.md @@ -16,7 +16,7 @@ Read a method and say what it does, in plain language. Reading costs nothing and - **A bundle directory needs no tool at all**: it is explained from its source, and `mthds_validate`, when present, adds the verdict line. Never refuse to explain a local bundle because the workshop is not connected. - **A catalog id or a published address needs the workshop**, since nothing of it is on disk. Where `mthds_get_method` is absent while the other tools answer, an id is explained at contract level, as an address is, and the explanation says which reading it is: a narrower explanation, not a stop. - **If the workshop is absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Codex. That stop is only for a target that lives on the platform — a bundle directory on disk is still explained from its source, with the verdict line left out. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Same scope: on a local bundle a `config` error costs the verdict line and nothing else — carry on and say it was not checked. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Same scope: on a local bundle such a problem costs the verdict line and nothing else — carry on and say it was not checked. ## Guards @@ -36,7 +36,7 @@ A `PipeSignature` is **pending only when no concrete pipe of the same code exist ### 3. The verdict, when the workshop is there -One `mthds_validate` call on the bundle directory. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. **From a folder, explain the `.mthds` files in `files_sent`, naming any you read that it leaves out.** **A single file goes as `files` instead**, its `{path}` and then those of the templates its steps name: its folder may hold other methods. The call adds two things to the explanation: the **verdict line** (whether it is valid, whether it is runnable, what is still pending) and, when the verdict carries a `main_pipe`, the **main pipe's typed signature**: its namespaced ref, each declared input with its concept and whether it is required, and the concept it produces. Into the method's directory the workshop also writes its flowchart as `method-graph.html`, rewritten on every validation, and reports it as `graph_page`. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `template_check_warning`. +One `mthds_validate` call on the bundle directory. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. **From a folder, explain the `.mthds` files in `files_sent`, naming any you read that it leaves out.** **A single file goes as `files` instead**, its `{path}` and then those of the templates its steps name: its folder may hold other methods. The call adds two things to the explanation: the **verdict line** (whether it is valid, whether it is runnable, what is still pending) and, when the verdict carries a `main_pipe`, the **main pipe's typed signature**: its namespaced ref, each declared input with its concept and whether it is required, and the concept it produces. Into the method's directory the workshop also writes its flowchart as `method-graph.html`, rewritten on every validation, and reports it as `graph_page`. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `pipelex.docgen.template_warning`. Without the tool, explain from the source and **say the verdict was not checked**. Your own reading of the source is not a guess: the pipe types, the concepts and step 2's backlog are yours to state, saying whose reading it is. But do not present a validation verdict, a typed signature or a pending list as the workshop's when the workshop did not answer, and do not guess at validity. **On a target that is not on disk there is no such fallback.** @@ -79,11 +79,11 @@ Output: final_output | the workshop is absent, on an id or an address | stop per the Requirements: there is nothing to read | | `mthds_get_method` is absent while the other tools answer | explain the id at contract level, say the source was not read, and name the cause [not-on-disk.md](references/not-on-disk.md) gives | | an id's source comes back `truncated` | name the files you could not read and say the explanation is partial. Never describe a withheld file's pipes as absent. | -| an id is refused at `method_id` | give the tool's answer: an unknown id and an empty stored source are different answers, and an empty one is somebody's draft, not a wrong id | -| a selector call answers a no-verdict error | report the error and its `hint` verbatim; hosted address and id resolution is not live everywhere yet | +| an id is refused | give the tool's answer: an unknown id (`pipelex.catalog.not_found`) and an empty stored source (`method.package_invalid`) are different answers, and an empty one is somebody's draft, not a wrong id | +| a selector call answers a no-verdict problem | report its `detail` and `next_step` verbatim; hosted address and id resolution is not live everywhere yet | | a **local bundle** does not validate | explain it anyway from the source, say what the verdict was, and route a fix to `/pipelex-edit` or `/pipelex-design` | -| a **catalog id** does not validate | explain it from the source read above with `validation_errors[]` beside it, and say the fix is not on this disk | -| a published **address** does not validate | report `validation_errors[]` and stop: there is no source to explain, and the fix is upstream | +| a **catalog id** does not validate | explain it from the source read above with its `errors[]` beside it, and say the fix is not on this disk | +| a published **address** does not validate | report its `errors[]` and stop: there is no source to explain, and the fix is upstream | | the verdict carries no `main_pipe` | say so, and which cause the tool's message points to: the method settles no entry pipe, the contract did not come back whole, or the workshop predates the field. Do not reconstruct a signature from the input template. | | the user wants the method changed, or a saved method's files on disk | route: `/pipelex-edit` for a contract-preserving fix, `/pipelex-design` for a structural one, `/pipelex-catalog` to bring a saved method to disk | diff --git a/pipelex-codex/skills/pipelex-explain/references/not-on-disk.md b/pipelex-codex/skills/pipelex-explain/references/not-on-disk.md index d2c8a31a..39b19058 100644 --- a/pipelex-codex/skills/pipelex-explain/references/not-on-disk.md +++ b/pipelex-codex/skills/pipelex-explain/references/not-on-disk.md @@ -6,7 +6,7 @@ The two targets part company on ownership rather than convenience. **A catalog i ## A catalog id: read it in full -Call `mthds_get_method` with the `method_id`, as the skill's step 1 says. The `files` it returns are explained **exactly as a bundle on disk is**, through the skill's steps 1 to 5, with the returned contents standing in for the files you would have read. The verdict of step 3 is one `mthds_validate` call naming the content that was read: `mt_…@draft` when the result's `version` is `draft`, and `mt_…@` for version n. A platform that does not resolve versions yet refuses the suffix, with a hint saying that a bare id reads the draft there: validate the bare id then, which reads the same stored content on that platform, and say so. +Call `mthds_get_method` with the `method_id`, as the skill's step 1 says. The `files` it returns are explained **exactly as a bundle on disk is**, through the skill's steps 1 to 5, with the returned contents standing in for the files you would have read. The verdict of step 3 is one `mthds_validate` call naming the content that was read: `mt_…@draft` when the result's `version` is `draft`, and `mt_…@` for version n. A platform that does not resolve versions yet refuses the suffix, the problem's `message` saying that a bare id reads the draft there: validate the bare id then, which reads the same stored content on that platform, and say so. **A bare id reads the draft here and the latest published version everywhere else.** `mthds_get_method` reads a bare id's draft, which is what the next save replaces, while a validation, an inputs template or a run of the same bare id reads the latest published version, what the method's callers run. So never validate a draft's source under the bare id, and say which content the explanation is of. The result's `publish_state` says how the two stand: `draft_ahead` means callers of the bare id run version `latest_version`, which differs from what you explained, so say so and offer to explain `mt_…@`; `draft_unchanged` means they run what you explained; `never_published` means a bare id runs nothing yet. @@ -18,7 +18,7 @@ Three things about the returned set are worth knowing before you describe it: ## Without `mthds_get_method` -When the other tools answer and `mthds_get_method` does not, read the id at contract level exactly as an address is read below, with `method_id` as the selector, and say that the source was not read rather than implying there was none to read. A bare id there is the latest published version, and one never published is refused as `method_not_published`, whose draft `mt_…@draft` can be read instead; say which you read. **The cause is a local workshop that predates the tool**, which `npx -y @pipelex/mcp@latest` refreshes; say so. The Pipelex connector's `pipelex_*` tools, when the session has them too, belong to a different server with no tool of this name, so they neither cause this nor stand in for the workshop. +When the other tools answer and `mthds_get_method` does not, read the id at contract level exactly as an address is read below, with `method_id` as the selector, and say that the source was not read rather than implying there was none to read. A bare id there is the latest published version, and one never published is refused as `pipelex.catalog.not_published`, whose draft `mt_…@draft` can be read instead; say which you read. **The cause is a local workshop that predates the tool**, which `npx -y @pipelex/mcp@latest` refreshes; say so. The Pipelex connector's `pipelex_*` tools, when the session has them too, belong to a different server with no tool of this name, so they neither cause this nor stand in for the workshop. ## A published address: its contract @@ -31,5 +31,5 @@ When the other tools answer and `mthds_get_method` does not, read the id at cont A published address has no source to fall back on, and neither has an id read at contract level, so these verdicts are said rather than filled in. An id read in full still has its source. - **The verdict is positive but carries no `main_pipe`.** The method settles no entry pipe, the contract did not come back whole, or the workshop predates the field — the same three causes `/pipelex-integrate` names, and the one-line signature in the text summary is missing in all three. Say the verdict was positive and that it carries no signature to describe the contract with, and name which of the three the tool's own message points to. -- **The verdict is `is_valid: false`.** There is no `main_pipe` on an invalid verdict and `mthds_inputs_template` answers with `validation_errors[]` rather than shapes, so nothing about the method is readable **from the verdict** — though for an id read in full the source still is, and an invalid stored method is worth explaining from its source with the errors beside it. Report the errors as they came back. **Do not route a remote target to `/pipelex-edit` or `/pipelex-design`**: a stored method is fixed where it is edited — `/pipelex-catalog` is what brings it to disk first — and a published address is fixed in the repository it names. -- **The id is refused rather than read.** An unknown id and a method whose stored source is empty both arrive as `input_domain` at `method_id`: the first says no such method is visible to the API key's organization, which a method from another organization reads exactly like; the second says the row exists and holds no source yet. Give the one the tool gave, as the skill's stop table says. +- **The verdict is `is_valid: false`.** There is no `main_pipe` on an invalid verdict and `mthds_inputs_template` answers with `errors[]` rather than shapes, so nothing about the method is readable **from the verdict** — though for an id read in full the source still is, and an invalid stored method is worth explaining from its source with the errors beside it. Report the errors as they came back. **Do not route a remote target to `/pipelex-edit` or `/pipelex-design`**: a stored method is fixed where it is edited — `/pipelex-catalog` is what brings it to disk first — and a published address is fixed in the repository it names. +- **The id is refused rather than read.** An unknown id and a method whose stored source is empty are told apart by the problem's `code`: the first is `pipelex.catalog.not_found`, no such method visible to the API key's organization, which a method from another organization reads exactly like; the second is `method.package_invalid` at `method_id`, the row existing and holding no source yet. Give the one the tool gave, as the skill's stop table says. diff --git a/pipelex-codex/skills/pipelex-inputs/SKILL.md b/pipelex-codex/skills/pipelex-inputs/SKILL.md index ee44e6eb..64fa5d35 100644 --- a/pipelex-codex/skills/pipelex-inputs/SKILL.md +++ b/pipelex-codex/skills/pipelex-inputs/SKILL.md @@ -11,8 +11,8 @@ The one entry point for a method's inputs, through to run-ready inputs. - **`mthds_inputs_template`** is required: never hand-derive the template from the `.mthds` source. - **If the tool is absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Codex. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never silently improvise a template. -- **`mthds_prepare_inputs`** is required at step 5, under the same two stops; never hand-fake a storage reference. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never silently improvise a template. +- **`mthds_prepare_inputs`** is required at step 5, under the same two stops, except `auth.forbidden` on a call with `kind` (see Stops); never hand-fake a storage reference. - **`mthds_list_methods`** and **`mthds_list_files`** are optional: without the first, ask for a saved method's `mt_…` id. ## Mode @@ -34,8 +34,8 @@ The one entry point for a method's inputs, through to run-ready inputs. The target takes three forms, one selector per call. - **A local bundle**, the usual case: `` is its directory, usually the one holding `main.mthds`, unless the caller names another. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. -- **A registered method**, an `mt_…` id with no local bundle in play, as `method_id`: bare, the latest published version; `@draft`, the draft; `@`, version n. **Say which one the template came from** (`method_version`) and offer the run on that same form; a bare id never published is refused as `method_not_published`, and `mt_…@draft` is then the target. `` is a directory the user names, by default a new `.//` without the suffix. -- **A published method**, as `method_ref: "github.com//[/][@]"`: read [references/published-address.md](references/published-address.md) before the first call. **An address with no tag is accepted, and it floats**: say so in one line, recommend the tag, and carry on. +- **A registered method**, an `mt_…` id with no local bundle in play, as `method_id`: bare, the latest published version; `@draft`, the draft; `@`, version n. **Say which one the template came from** (`method_version`) and offer the run on that same form; a bare id never published is refused as `pipelex.catalog.not_published`, and `mt_…@draft` is then the target. `` is a directory the user names, by default a new `.//` without the suffix. +- **A published method**, as `method_ref: "github.com//[/][@]"`: read [published-address.md](references/published-address.md) before the first call. **An address with no tag is accepted, and it floats**: say so in one line, recommend the tag, and carry on. ### 2. The template @@ -53,8 +53,8 @@ Evaluated in order: | No clear signal (e.g. right after `/pipelex-design`, with no further context) | **Template**, then offer to populate | - **Template**: replace each file-ish mock URL (an `https://` URL on a `.invalid` host) with `""`, never `""`; save, show it with its path, and offer synthetic data or the user's files. -- **Synthetic**: read [references/synthetic.md](references/synthetic.md) before generating anything. **`pipelex-synthetic-inputs` is the file factory**, and makes every file input. Codex has no cross-skill invocation, so open `../pipelex-synthetic-inputs/SKILL.md` and follow it. -- **User data**: read [references/user-data.md](references/user-data.md) before matching any file to an input. +- **Synthetic**: read [synthetic.md](references/synthetic.md) before generating anything. **`pipelex-synthetic-inputs` is the file factory**, and makes every file input. Codex has no cross-skill invocation, so open `../pipelex-synthetic-inputs/SKILL.md` and follow it. +- **User data**: read [user-data.md](references/user-data.md) before matching any file to an input. - **Mixed**: the user's files first, then synthetic values for what they leave unfilled; read both references. - **The team's files**: read [team-files.md](../shared/team-files.md) before asking for a file, or for one named but not on disk. @@ -64,7 +64,7 @@ Fill the step 2 template in place, a composite native's fields included ([native ### 5. Prepare the inputs for a run -`mthds_prepare_inputs` uploads each local path, `data:` URL or inline bytes at a file input to Pipelex storage. Skip the call for the Template strategy. Otherwise, for a case's copies, **first delete any `inputs.prepared.json` an earlier prepare left in ``**, which a run would read after a prepare that writes none. Skip the call too **when every file-ish value is already an `http(s)` URL or a `pipelex-storage://` reference**: a run then reads `inputs.json`. +`mthds_prepare_inputs` uploads each local path, `data:` URL or inline bytes at a file input to Pipelex storage. Skip the call for the Template strategy. Otherwise, for a case's copies, **first delete any `inputs.prepared.json` an earlier prepare left in ``**. Skip the call too **when every file-ish value is already an `http(s)` URL or a `pipelex-storage://` reference**: a run then reads `inputs.json`. **Say what is about to leave the machine, before it does**: each file and where it goes (Pipelex storage, the user's organization, through their API key), or for a folder batch too long to list, the count and the folder; in interactive mode wait for a yes, in automatic mode state it and proceed. If the user declines, stop before the call and report that the inputs stay local and are not runnable. @@ -84,24 +84,25 @@ Say what is ready, or which placeholders are left. When a codebase here does not - no calling skill asked to stop at run-ready (a user who said not to run still gets the offer: an offer is not a run); - no placeholder remains; -- **every input the template asked for is filled** — one the factory could not make is absent, passes every other check and guarantees a failed run: say which input waits on the user, and why; +- **every input the template asked for is filled** — one the factory could not make is absent: say which input waits on the user, and why; - the inputs are run-ready: prepare succeeded, or step 5 skipped it because nothing needed uploading. -The offer names the file the run reads — `inputs.prepared.json` where prepare wrote one, else `inputs.json` — and the target: the bundle, the id or the address. +The offer names the file the run reads — `inputs.prepared.json` where prepare wrote one, else `inputs.json` — and the target. ## Stops | Condition | Do this | |---|---| -| template: `is_valid: false` | report `validation_errors[]` and the summary. A local bundle is repaired first (`/pipelex-design` resumes it), then retried; a registered method through `/pipelex-edit`, not here; a published one is reported as [its reference](references/published-address.md) says | -| template: `input_domain` | an unknown `pipe_ref` or unresolvable `main_pipe`: pass an explicit `pipe_ref`. At `method_dir`, `method_id` or `method_ref`, report it in the tool's words; another organization's id reads as a miss | -| `runtime`, either call | report, and retry once | +| template: `is_valid: false` | report `errors[]` and the summary. A local bundle is repaired first (`/pipelex-design` resumes it), then retried; a registered method through `/pipelex-edit`, not here; a published one is reported as [its reference](references/published-address.md) says | +| template: `request.pipe_not_found` or `request.pipe_ambiguous` | pass an explicit `pipe_ref`. Another `domain: "input"` problem: report it in the tool's words; another organization's id reads as a miss | +| `retry: "yes"`, either call | report, and retry once | | the factory returns no path | leave that one input unfilled, carry on with the others; report the reason and ask for the user's own file. Never fabricate a value or abandon `inputs.json` | -| prepare: `input_domain` at `inputs`, `pipe_ref`, `method_id` or `method_ref` | read [references/prepare-errors.md](references/prepare-errors.md) before replying or retrying; a storage size limit at `inputs` is terminal for this attempt | -| prepare, by address: `input_domain` at `files`, or `config` (the credential first, as the requirements say) | read [references/published-address.md](references/published-address.md) before naming a cause | +| prepare with `kind`: `auth.forbidden`, or a refusal naming `kind`, or `method_id` for `method_not_found`, `method_being_deleted` or `version_suffix` | read [synthetic.md](references/synthetic.md#test-files) before preparing again without `kind` | +| prepare: an `input` or `method` problem, not a refusal of `kind` | read [prepare-errors.md](references/prepare-errors.md) before replying or retrying; a storage size limit at `inputs` is terminal for this attempt | +| prepare, by address: refused at `files`, or an `account` problem | read [published-address.md](references/published-address.md) before naming a cause | ## References -- [synthetic.md](references/synthetic.md), [user-data.md](references/user-data.md): step 3, by strategy; both for Mixed. +- [synthetic.md](references/synthetic.md), [user-data.md](references/user-data.md): step 3, by strategy. - [published-address.md](references/published-address.md): a `method_ref` target. -- [prepare-errors.md](references/prepare-errors.md): prepare's `input_domain` errors. +- [prepare-errors.md](references/prepare-errors.md): prepare's input and method problems. diff --git a/pipelex-codex/skills/pipelex-inputs/references/prepare-errors.md b/pipelex-codex/skills/pipelex-inputs/references/prepare-errors.md index 11396395..d6f6919d 100644 --- a/pipelex-codex/skills/pipelex-inputs/references/prepare-errors.md +++ b/pipelex-codex/skills/pipelex-inputs/references/prepare-errors.md @@ -1,25 +1,27 @@ # When preparation fails -Read this when `mthds_prepare_inputs` answers `status: "error"` with class `input_domain` located at `inputs`, `pipe_ref`, `method_id` or `method_ref`, before replying to the user or retrying. Unlike `mthds_inputs_template`, the tool has no produced-invalid arm: it never returns a `validation_errors[]` list. **Read the error's `location` first**, because the causes need opposite repairs. The skill's file-fidelity guard holds throughout: nothing here is a reason to transform, derive or substitute a file, or to retry with one. +Read this when `mthds_prepare_inputs` answers `status: "error"` with a problem the inputs or the method's resolution must fix (its `domain` is `input` or `method`), before replying to the user or retrying. Unlike `mthds_inputs_template`, the tool has no produced-invalid arm: it never returns a verdict with `errors[]` of its own. **Read the problem's `code` first**, because the causes need opposite repairs; the location and the wording never tell them apart. A refusal of `kind` is not this file's: on a call that passed `kind: "test"`, `client.argument_invalid` whose `params.argument` is `kind`, or is `method_id` with `params.reason` `method_not_found`, `method_being_deleted` or `version_suffix`, and `auth.forbidden` are about recording test files, which the skill answers where it passes `kind`. The skill's file-fidelity guard holds throughout: nothing here is a reason to transform, derive or substitute a file, or to retry with one. -## `location: "inputs"` and the response reports a storage size limit +## `upload_too_large`: a file over the storage size limit -This is a terminal branch for the current preparation attempt. +The workshop refuses a file over the upload ceiling before anything is sent, as `client.argument_invalid` at `inputs` whose `params.reason` is `upload_too_large`. This is a terminal branch for the current preparation attempt. -1. Report the affected input and file; quote the tool's exact `message` and `hint` verbatim; and include the actual file size and the allowed limit whenever the response provides them, whether as fields or inside those diagnostics. +1. Report the affected input and file; quote the tool's exact `message` and `next_step` verbatim; and include the actual file size and the allowed limit whenever the response provides them, whether as fields or inside those diagnostics. 2. State explicitly that preparation failed, the inputs are not run-ready, and no run will be offered. 3. Make no follow-up file writes: preserve the user's original file, and a case's copy of it, unchanged, and write no `inputs.prepared.json` for a case (the skill's step 5 deleted any earlier one before the call) — nothing downstream then mistakes these inputs for run-ready, and `inputs.json` keeps its local-path form because step 5 writes the prepared values only on success. 4. Continue only after the user supplies a different acceptable input or reference, or the service limit changes. -## `location: "inputs"` and the response is not a size-limit failure +## A file the walk could not read or take -Surface the exact `message` and `hint`, then follow only the recovery they support. +Surface the exact `message` and `next_step`, then follow only the recovery they support. -- **For an unreadable local file**, verify that the same file exists, resolve its path to absolute as step 5 does, and retry preparation with the file bytes unchanged. A relative path sent as-is fails this way, as `Local file cannot be read: "inputs/cv.pdf" (ENOENT)`, because the workshop resolves it against its own working directory. The correction is to the request alone, and it must not rewrite the local relative path in `inputs.json`. -- **For any other asset failure**, retry only when the documented error policy explicitly permits a recovery that preserves the asset's content and identity. +- **For an unreadable local file**, `input.file_unreadable` naming the path, verify that the same file exists, resolve its path to absolute as step 5 does, and retry preparation with the file bytes unchanged. A relative path sent as-is fails this way, as `Local file cannot be read: "inputs/cv.pdf" (ENOENT)`, because the workshop resolves it against its own working directory. The correction is to the request alone, and it must not rewrite the local relative path in `inputs.json`. +- **For a value no file input takes**, `input.invalid` naming the input, such as a `data:` URL that does not decode, fix that value in the request from the user's own file or reference. +- **For any other asset failure**, retry only when the documented error policy explicitly permits a recovery that preserves the asset's content and identity: the problem's `retry` is `"yes"`, or its `next_step` names one. The method is not at fault, so don't revalidate it: `mthds_validate` and `mthds_inputs_template` only inspect the method definition, and they will keep answering "valid" while the same asset keeps failing. -## `location: "pipe_ref"`, `"method_id"` or `"method_ref"` +## The method or its pipe did not resolve + +`method.invalid` is a closure that does not load, its `errors` the closure's faults; `request.pipe_not_found` and `request.pipe_ambiguous` are an unknown `pipe_ref` or a method that settles no entry pipe or several, with the pipes the route suggests in its `params`; `pipelex.catalog.not_found` is an id the organization does not hold; and an address that did not resolve is the runner's own problem, located at `method_ref`. This is the arm whose diagnostics the tool delegates: get the structured errors from `mthds_validate` or `mthds_inputs_template`, repair, then retry. For an address the repair is not yours to make: report it with the address and the tag. -The closure did not resolve: an invalid bundle, an unknown `pipe_ref`, an unresolvable `main_pipe`, a method id with no stored source, or an address that did not resolve. This is the arm whose diagnostics the tool delegates: get the structured errors from `mthds_validate` or `mthds_inputs_template`, repair, then retry. For an address the repair is not yours to make: report it with the address and the tag. diff --git a/pipelex-codex/skills/pipelex-inputs/references/published-address.md b/pipelex-codex/skills/pipelex-inputs/references/published-address.md index d4081f83..a664b1ec 100644 --- a/pipelex-codex/skills/pipelex-inputs/references/published-address.md +++ b/pipelex-codex/skills/pipelex-inputs/references/published-address.md @@ -1,6 +1,6 @@ # A published address -Read this at step 1 when the target is a published method's address, passed as `method_ref`, before the first call; and again when `mthds_prepare_inputs` refuses the address in one of the two ways only an address meets. An address is passed exactly as a catalog id is, so every step runs as the skill says; what follows is where an address is genuinely not like an id. +Read this at step 1 when the target is a published method's address, passed as `method_ref`, before the first call; and again when `mthds_prepare_inputs` refuses the address, before naming a cause. An address is passed exactly as a catalog id is, so every step runs as the skill says; what follows is where an address is genuinely not like an id. ## Where the inputs go @@ -8,14 +8,14 @@ The server fetches the repository at the tag and locates the package there, so t ## A template that does not validate -When `mthds_inputs_template` answers `is_valid: false` on an address, the package at that address does not validate: report `validation_errors[]` with the address and its tag, and say the fix is upstream or another tag — never a local repair of source the user does not have. +When `mthds_inputs_template` answers `is_valid: false` on an address, the package at that address does not validate: report its `errors[]` with the address and its tag, and say the fix is upstream or another tag — never a local repair of source the user does not have. -## Prepare, `input_domain` at `files`: a workshop older than the selector +## Prepare refused at `files`: a workshop older than the selector -`mthds_prepare_inputs` took `files` and `method_id` alone until the release that gave it the address, so a workshop cached from before then does not know `method_ref` — and a host that validates a call against that older tool schema drops the argument before it is ever sent. The tell is the error itself: `input_domain` located at **`files`**, saying *"Provide MTHDS files or a method_id"*, on a call that did supply a selector — the message lists what the tool accepts and leaves `method_ref` out of it. Read it as a workshop that predates the selector, not as a missing target. The same address goes on templating normally throughout, because `mthds_inputs_template` has taken it for longer — which is what makes the pair of answers the diagnosis. +`mthds_prepare_inputs` took `files` and `method_id` alone until the release that gave it the address, so a workshop cached from before then does not know `method_ref` — and a host that validates a call against that older tool schema drops the argument before it is ever sent. The tell is the error itself: located at **`files`**, saying *"Provide MTHDS files or a method_id"*, on a call that did supply a selector — the message lists what the tool accepts and leaves `method_ref` out of it. Read it as a workshop that predates the selector, not as a missing target. The same address goes on templating normally throughout, because `mthds_inputs_template` has taken it for longer — which is what makes the pair of answers the diagnosis. Give the cure with both of its conditions: the launcher fetches the newest workshop only on its next spawn, so `npx -y @pipelex/mcp@latest` changes nothing until the host restarts the server and reloads its tool schema — and a refresh only reaches the selector once a published workshop carries `method_ref` on prepare at all. Where none does yet, say that this one leg is unavailable rather than leaving them refreshing in a loop, and never fall back to submitting files you do not have. -## Prepare, class `config`: the credential first, then the deployment +## Prepare, a problem in the `account` domain: the credential, and only the credential -The skill's `config` stop applies as written: surface the `hint` verbatim and deal with the credential first, since it is the one thing the user can act on. But a by-address target has one further cause here, and nothing in the answer yet tells you which of them you met. Preparation resolves an address's signature through the run route, which refuses a published package shipping in-process Python where the deployment hosts no sandbox — and that refusal arrives in this same `config` arm wearing the deployment's authentication wording. A template call that just succeeded on the same address rules nothing out, because preparation also uploads with the key and templating never exercises that. So once the key proves good, name the other cause rather than leaving the user with a mystery: a published package can be refused by the deployment itself, and one carrying no in-process Python is not affected. +The skill's account stop applies as written: relay the `next_step` verbatim and deal with the credential first, since it is the one thing the user can act on. A template call that just succeeded on the same address rules nothing out, because preparation also uploads with the key and templating never exercises that. What the problem names is the whole cause: preparation reads an address's signature from the package's `.mthds` files alone, so the deployment's refusal of a package shipping in-process Python never reaches it. That refusal, `pipelex.deployment.custom_code_requires_sandbox`, meets the run instead, which says so in its own words. diff --git a/pipelex-codex/skills/pipelex-inputs/references/synthetic.md b/pipelex-codex/skills/pipelex-inputs/references/synthetic.md index 7d679b3f..f42cd330 100644 --- a/pipelex-codex/skills/pipelex-inputs/references/synthetic.md +++ b/pipelex-codex/skills/pipelex-inputs/references/synthetic.md @@ -52,7 +52,7 @@ Step 5 uploads the factory's files as test files of the method, so the team's fi - **A published address, or an id with a suffix (`mt_…@draft`, `mt_…@`)**: leave `kind` out. An address names no saved method, and the workshop refuses a suffixed id beside `kind`, at `method_id`. The factory's files then go up as the organization's own files. - **Mixed, with the user's own files to upload as well**: `kind` applies to every upload of a call, and the user's files are theirs, not test files. Prepare in two calls: first the inputs holding the factory's files, alone, with `kind: "test"`; then every input, without `kind`, with those inputs' prepared values in place of their paths, which the second call passes through unchanged. Write the second call's `inputs` as step 5 says, and nothing when either call fails. -- **Refused over `kind`**, as `input_domain` at `kind`, or as a `config` error tagged `kind: "role"`: no file was recorded. The first means no saved method could be named, because the folder is linked to none, its link cannot be read, was made against another API or is still the older `pipelex-method.json`, or the platform no longer holds the method; the second means the user's role may not record test files, which is no problem with the key. Prepare again without `kind`, and say in one line that the factory's files went up as the organization's own and why, in the refusal's words, relaying its hint, such as saving the method so that its folder is linked, as the user's to act on, never yours. +- **Refused over `kind`**, as `client.argument_invalid` at `kind` or at `method_id` with `params.reason` `method_not_found`, `method_being_deleted` or `version_suffix`, or as `auth.forbidden`: no file was recorded. The first means no saved method could be named, its `params.reason` saying why: the folder is linked to none, its link cannot be read, was made against another API or is still the older `pipelex-method.json`; at `method_id`, its `params.argument` naming it, the platform no longer holds the method or is erasing it, or the id carries a suffix; the last means the user's role may not record test files, which is no problem with the key. Prepare again without `kind`, and say in one line that the factory's files went up as the organization's own and why, in the refusal's words, relaying its `message`, such as saving the method so that its folder is linked, as the user's to act on, never yours. Any other refusal at `method_id`, such as `not_a_catalog_id`, is a fault of the target that dropping `kind` does not cure: the skill's stop table routes it. - **No `kind` in the answer**: a workshop older than test files drops the argument, uploads the files as the organization's own and echoes no `kind`. The inputs are run-ready all the same, so do not prepare again: say in one line that `npx -y @pipelex/mcp@latest` refreshes the workshop once the host restarts the server and reloads its tools, and that the next preparation then records test files. When the answer carries `test_method_id`, step 5's report says the files went up as test files of that method. The report gives each generated file's temporary path, for a user who wants to open it before the run, and its name among the team's files, its file name, under which it is listed with the method. diff --git a/pipelex-codex/skills/pipelex-integrate/SKILL.md b/pipelex-codex/skills/pipelex-integrate/SKILL.md index 5e637f67..a7c2a4d5 100644 --- a/pipelex-codex/skills/pipelex-integrate/SKILL.md +++ b/pipelex-codex/skills/pipelex-integrate/SKILL.md @@ -12,7 +12,7 @@ Leave a project calling a method through one typed module, over generated types ## Requirements - **If a tool is absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Codex. -- **If a call returns `status: "error"` with an error of class `config`**, STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. A **403** on `mthds_codegen` is a feature gate, not a key problem. +- **If a call returns a problem in the `account` domain, or `client.unreachable`**, STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. A **403** on `mthds_codegen` is a feature gate, not a key problem. - **`mthds_list_methods`** is optional, for a method named without its id; never stop for it. ## Guards @@ -75,7 +75,7 @@ Put the generated directory and the gate script step 10 copies in the formatter' - `status: "ok"`, `is_valid: true`, `output_dir` present → written; clean when `is_current: true` with an empty `orphans[]`. - **`orphans[]` non-empty and `drifts[]` empty** → carry on to step 7 and read [references/orphans.md](references/orphans.md). Read it off the two lists, never from `is_current`; `drifts[]` is present only when non-empty, so no `drifts` is the empty case. -- **`output_dir already holds …, which this tool does not own`** → that file is the user's: never delete, move or clear it, and never offer to; choose or ask for another directory, before the call too. +- **`client.target_exists`, a file this tool does not own** → that file is the user's: never delete, move or clear it, and never offer to; choose or ask for another directory, before the call too. - anything else (`drifts[]` included) → the stops. ### 7. The sidecar @@ -126,10 +126,10 @@ What was generated and where, the target and why, the call site's signature, the | Condition | Do this | |---|---| -| invalid, unrunnable, or `pending_signatures` | STOP, nothing generated: `validation_errors[]` to `/pipelex-design` or `/pipelex-edit`, else finish it in `/pipelex-design` | -| `input_domain` at `method_ref` / `method_id` | report it in the tool's words | -| `runtime` | retry once (codegen: only if `retryable: true`, same `output_dir`), then report what landed | -| `input_domain` at `output_dir`, outside the server's directory | step 1's containment: STOP, relaunch, say what is already written | +| invalid, unrunnable, or `pending_signatures` | STOP, nothing generated: `errors[]` to `/pipelex-design` or `/pipelex-edit`, else finish it in `/pipelex-design` | +| `domain: "input"` on `method_ref` / `method_id` | report it in the tool's words | +| `retry: "yes"`, or codegen's `client.write_failed` | retry once (codegen: same `output_dir`), then report what landed | +| `outside_workspace` at `output_dir` | step 1's containment: STOP, relaunch, say what is already written | | `is_current: false`, not step 6's orphans case | report `drifts[]` verbatim and stop; commit nothing | | no signature, by address or id | STOP as the fallback reference says; never guess the output concept | | `python-structures`, its `pipelex-sdk` after step 8 unread or below the floor, templated bundle | STOP, nothing generated: [python.md](references/python.md) | diff --git a/pipelex-codex/skills/pipelex-lab/SKILL.md b/pipelex-codex/skills/pipelex-lab/SKILL.md index 8bfda5a4..b6e699ac 100644 --- a/pipelex-codex/skills/pipelex-lab/SKILL.md +++ b/pipelex-codex/skills/pipelex-lab/SKILL.md @@ -14,7 +14,7 @@ Start where the project stands: when `lab//` exists, read it and take up The loop needs the workshop: `/pipelex-run` starts and follows each run, and this skill reads each result with **`mthds_run_results`**, and with `mthds_run_status` and `mthds_download_artifacts`. - **If those tools are absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Codex. That stop comes at the loop: framing and setting up need no tool, so frame and set up, then stop before the loop. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. ## The lab directory diff --git a/pipelex-codex/skills/pipelex-lab/references/log.md b/pipelex-codex/skills/pipelex-lab/references/log.md index cee870fe..91d1e517 100644 --- a/pipelex-codex/skills/pipelex-lab/references/log.md +++ b/pipelex-codex/skills/pipelex-lab/references/log.md @@ -30,7 +30,7 @@ Failed: M3 (the memo puts the relocation clause below the medium items). Partial - **The duration** runs from the status's `created_at` to its `finished_at`. - **The score** is the Must and Must not lines passed, out of the case's Must and Must not lines. A reading an Also acceptable line allows passes the line it names, and planted facts are not scored. Partial and unscored lines count as not passed, toward the round's score and toward the pass bar, except a line the pass bar allows to be partial, which meets the bar when it is partial. - **A cut output** adds a line: "Output cut at the size cap: M4 and M6 unscored." -- **A failed run** is logged with the status and the first line of its `failure_message`, as `FAILED · …`, and scores nothing. +- **A failed run** is logged with the status and its problem's `code` and `title`, from `run_error` or the status's `error`, as `FAILED · …`, and scores nothing. - **An unfinished run** is logged as `UNFINISHED · still RUNNING after …`, with its run id, so that `/pipelex-run` can follow it later. ## A run the loop did not start diff --git a/pipelex-codex/skills/pipelex-organize/SKILL.md b/pipelex-codex/skills/pipelex-organize/SKILL.md index 001ebb82..56ecd959 100644 --- a/pipelex-codex/skills/pipelex-organize/SKILL.md +++ b/pipelex-codex/skills/pipelex-organize/SKILL.md @@ -13,7 +13,7 @@ It is a **content-preserving transformation**: the method's semantics never chan - **`mthds_validate`** is required: this skill never reorganizes without proving the verdict is preserved. - **If the tool is absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Codex. Do not touch the bundle files without validation available. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never reorganize unvalidated. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never reorganize unvalidated. ## Guards @@ -62,14 +62,14 @@ One short summary: the layout, one line per file saying what it holds, and the p **When invoked on its own rather than by `/pipelex-design`** (whose delivery step carries both notices), end with them, since an identical verdict still rewrote every file: 1. Search the whole project for `sources.json` files carrying `"generator": "pipelex-integrate"` — `grep -rl '"pipelex-integrate"' --include=sources.json .` — which sit beside each generated tree, never beside the bundle. Keep each one whose `sources` name a `.mthds` file this change rewrote, moved or removed, or whose `templates` name a template file it changed, **or whose `bundle_dir` holds a `.mthds` file this change created** — a new file is in no `sources` map, yet the call site loads every `.mthds` file under that directory. For each, say the generated types in that directory are now stale and offer `/pipelex-integrate` to refresh them: it regenerates in place and touches the call site only if the types no longer fit it. -2. **Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a `config`-class error included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. +2. **Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a problem in the `account` domain included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. ## Stops | Condition | Do this | |---|---| | `is_valid: false` at the baseline | never reorganize a broken library: report the verdict and point to `/pipelex-design` to fix it first | -| `status: "error"`, class `input_domain` | fix the call | -| `status: "error"`, class `runtime` | report it, and retry once before stopping | +| `status: "error"`, `domain: "input"` | fix the call | +| any other `status: "error"` | report it, after one retry when its `retry` is `"yes"` | | the candidate still differs from the baseline after two fixes of the composition | stop, leave the original layout untouched, and report the discrepancy | | the regrouping seems to need a semantic edit (a rename, a contract fix, a missing declaration) | stop and report it: that is `/pipelex-design`'s work | diff --git a/pipelex-codex/skills/pipelex-run/SKILL.md b/pipelex-codex/skills/pipelex-run/SKILL.md index f3cec457..e51fa965 100644 --- a/pipelex-codex/skills/pipelex-run/SKILL.md +++ b/pipelex-codex/skills/pipelex-run/SKILL.md @@ -11,7 +11,7 @@ This skill owns the run lifecycle: Start a run from a target and its inputs, or - **`mthds_run`**, **`mthds_run_status`** and **`mthds_run_results`** are required, and to start a run **`mthds_validate`** and **`mthds_inputs_template`** too: they keep credit from being spent on a method or inputs that cannot work. - **If the run tools are absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Codex. Never improvise a run id, a status or an output. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. - **`mthds_download_artifacts`**, **`mthds_list_methods`**, **`mthds_list_files`**: optional, never stop for one. ## Start a run @@ -26,7 +26,7 @@ The pipe is the declared main pipe unless the user named another: **carry its `p For a **bundle directory**, **first write a `.gitignore` holding `*` into each `runs/` in it that lacks one and whose folders hold `main_stuff.json`; add `*` to the `.gitignore` of each `inputs/` beside an `inputs.json`, and `/inputs.prepared.json` to the one beside that file, wherever the line is missing**, saying so, then one `mthds_validate` call on it. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. For an **`mt_…` id**, the same call with `method_id` in place of `method_dir`; for an address, `method_ref`. -The bar is `is_valid: true`, `is_runnable: true` and an empty `pending_signatures`. Short of it, report the verdict and route to `/pipelex-design`, or to `/pipelex-edit` when the fix is contract-preserving; an address's verdict is reported as [its reference](references/published-address.md) says. Never run a method that did not pass. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `template_check_warning`. +The bar is `is_valid: true`, `is_runnable: true` and an empty `pending_signatures`. Short of it, report the verdict and route to `/pipelex-design`, or to `/pipelex-edit` when the fix is contract-preserving; an address's verdict is reported as [its reference](references/published-address.md) says. Never run a method that did not pass. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `pipelex.docgen.template_warning`. **A dry run is this step, shown.** A run on test files is a real run. **When the verdict carries `graph_page.written: true`, give the page's `path` before the text flow**, for a browser to open. Pass on a new page's note that a project under git may want to ignore it. A `graph_page.error` gets one line, and the verdict stands. Show the flow as numbered text: each step, what it reads and makes, where it batches or branches, and which steps call a model. For an id or an address, give the contract from the verdict's `main_pipe` instead. Say that no model ran and nothing was spent. **Then end the turn there, even when the same request asked for the real run too**: the flow is the reply, and the paid run waits for the user's go. @@ -75,7 +75,7 @@ When the inputs came from a lab case and the lab did not start this run, offer ` ### 8. A failed run is reported, then routed, never bisected -Give `failure_message` **verbatim** first, then read [failed-run.md](references/failed-run.md) before routing it; route once, and stop. When the method holds a `PipeFunc`, name it as a suspect: **`PipeFunc` is experimental on the hosted plane.** Its Python runs in a sandbox with no network access, and the feature is still in development, so a method that validates can still fail when it runs. Per-pipe bisection is not this skill's. Do not re-run a failed method with altered inputs to see what happens — that spends credit on a guess. +Give the run's `run_error` **verbatim** first, then read [failed-run.md](references/failed-run.md) before routing it; route once, and stop. When the method holds a `PipeFunc`, name it as a suspect: **`PipeFunc` is experimental on the hosted plane.** Its Python runs in a sandbox with no network access, and the feature is still in development, so a method that validates can still fail when it runs. Per-pipe bisection is not this skill's. Do not re-run a failed method with altered inputs to see what happens — that spends credit on a guess. ## Follow a run @@ -91,7 +91,7 @@ An unknown run id is reported in the tool's own words. | Condition | Do this | |---|---| -| `mthds_run`: `input_domain` at `method_id`, on a linked run | nothing was spent: read [linked-run.md](references/linked-run.md) before replying | +| `mthds_run`: `pipelex.catalog.not_found`, on a linked run | nothing was spent: read [linked-run.md](references/linked-run.md) before replying | | `mthds_download_artifacts` absent | say nothing was saved to disk and report the stored references as they came back; the run still completed | | `mthds_download_artifacts` refuses a `dir` the user named | take step 7's ignore check, then call again without it, which saves into `runs//`, and say so. A refused `dir` is not a failed save | @@ -99,4 +99,4 @@ An unknown run id is reported in the tool's own words. - [by-id.md](references/by-id.md), [published-address.md](references/published-address.md): an `mt_…` or a `method_ref` target, before the first call. - [failed-run.md](references/failed-run.md): a failed run, before routing it. -- [linked-run.md](references/linked-run.md): a linked run refused at `method_id`. +- [linked-run.md](references/linked-run.md): a linked run whose id is unknown. diff --git a/pipelex-codex/skills/pipelex-run/references/by-id.md b/pipelex-codex/skills/pipelex-run/references/by-id.md index fa25f1b2..7ea15209 100644 --- a/pipelex-codex/skills/pipelex-run/references/by-id.md +++ b/pipelex-codex/skills/pipelex-run/references/by-id.md @@ -16,15 +16,15 @@ When the user named no directory, its inputs are looked for under the bare id wh ## A method never published -A bare id of a method with no published version is refused at step 2 as `method_not_published`, and nothing is spent. Its only content is its draft: say so, carry `mt_…@draft` through every call from step 2 on, and name it in step 4's line, so the user sees that the draft is what runs. Publishing is `/pipelex-catalog`'s, on the user's request, and never a way to make a bare id run. +A bare id of a method with no published version is refused at step 2 as `pipelex.catalog.not_published`, and nothing is spent. Its only content is its draft: say so, carry `mt_…@draft` through every call from step 2 on, and name it in step 4's line, so the user sees that the draft is what runs. Publishing is `/pipelex-catalog`'s, on the user's request, and never a way to make a bare id run. ## A version the method never had -`mt_…@` for a version that does not exist is refused at `method_id` as `method_version_not_found`, and the message names the versions the method has. Nothing is spent: report it and ask which one to run. +`mt_…@` for a version that does not exist is refused as `pipelex.catalog.not_found` whose `params.resource` is `version`. Nothing is spent: report it in the tool's words and ask which one to run. ## A platform that does not resolve versions yet -Such a platform refuses `@draft` and `@`, and the hint says that a bare id reads the draft there. Report it in the tool's words; on that platform the bare id runs the draft. +Such a platform refuses `@draft` and `@`, and the problem's `message` says that a bare id reads the draft there. Report it in the tool's words; on that platform the bare id runs the draft. ## Which version ran diff --git a/pipelex-codex/skills/pipelex-run/references/failed-run.md b/pipelex-codex/skills/pipelex-run/references/failed-run.md index d35126b4..d5c50fb3 100644 --- a/pipelex-codex/skills/pipelex-run/references/failed-run.md +++ b/pipelex-codex/skills/pipelex-run/references/failed-run.md @@ -1,6 +1,10 @@ # A failed run -Read this at step 8 when a run failed, after giving its `failure_message` verbatim and before routing it. Route once, on what the failure says, and stop; the guards of the skill's step 8 hold throughout. +Read this at step 8 when a run failed, after giving its problem verbatim and before routing it. Route once, on what the failure says, and stop; the guards of the skill's step 8 hold throughout. + +The problem the run ended with is `run_error` on the failed state of `mthds_run_results`, `mthds_show_images` and `mthds_download_artifacts`, and `error` on `mthds_run_status`: its `code` (such as `run.timed_out`, `run.cancelled` or `model.unavailable`), its `domain` and `retry`, its `title`, `detail` and `next_step`, and its `errors`, the run's faults, of which `errors_omitted` counts those left out. The tool's summary renders it and closes with a support line, the run id, the code and the time the run ended: keep that line in the report, since it is what the people who run the platform find the run by. A run that stored no problem carries its status alone, and the summary says so. + +**Read the `domain` beside the wording.** `input` says the inputs must change and `method` that the method must; `runtime`, `account` and `operator` point away from both, at a provider, a quota, the organization's account or the platform, which is reported with its `next_step` rather than routed, unless the failure's own words match a row below. | What the failure says | Where it goes | |---|---| @@ -13,7 +17,7 @@ Read this at step 8 when a run failed, after giving its `failure_message` verbat A folder, like listed `files`, sends `.mthds` files and the templates their steps name, never a `.py` file, and a linked id fetches nothing: a caller-supplied source takes precedence over the stored method, which is read only when no folder or files were sent at all, so a linked run gains its history entry and nothing else, the stored `.py` files included. A bundle whose `PipeFunc` names a module of its own folder therefore has **no channel for its Python on any run of the directory**, linked or not. The path that carries it is `/pipelex-catalog`: a saved method run by its id alone has its `.mthds` and `.py` assembled into the run bundle server-side, the draft's as `mt_…@draft` and a version's once it is published. -So on a run of the directory the suspicion sharpens, but only when the failure says so. Where `failure_message` implicates finding or importing that function or its module, say that as the cause rather than offering it as one candidate among several, and give the cure: `/pipelex-catalog` saves the bundle with its Python as the method's draft, and `mt_…@draft`, run by its id alone, gets both. **Where it says anything else, route on what it says** — a missing input, a model or prompt fault, a failure upstream of the custom pipe — and leave the `PipeFunc` a suspect rather than promoting it: a bundle holding one is not evidence that it is what failed, and saving it with its Python cures nothing but that. +So on a run of the directory the suspicion sharpens, but only when the failure says so. Where the run's problem implicates finding or importing that function or its module, say that as the cause rather than offering it as one candidate among several, and give the cure: `/pipelex-catalog` saves the bundle with its Python as the method's draft, and `mt_…@draft`, run by its id alone, gets both. **Where it says anything else, route on what it says** — a missing input, a model or prompt fault, a failure upstream of the custom pipe — and leave the `PipeFunc` a suspect rather than promoting it: a bundle holding one is not evidence that it is what failed, and saving it with its Python cures nothing but that. ## A published address diff --git a/pipelex-codex/skills/pipelex-run/references/linked-run.md b/pipelex-codex/skills/pipelex-run/references/linked-run.md index eb68719f..35ccf212 100644 --- a/pipelex-codex/skills/pipelex-run/references/linked-run.md +++ b/pipelex-codex/skills/pipelex-run/references/linked-run.md @@ -1,7 +1,7 @@ -# A linked run refused at `method_id` +# A linked run whose id is unknown -Read this when `mthds_run` refuses a run that sent a linked directory as `method_dir` beside the `method_id` of its `pipelex-method.json` with an `input_domain` error located at `method_id`, before replying. Nothing was spent. +Read this when `mthds_run` refuses a run that sent a linked directory as `method_dir` beside the `method_id` of its `pipelex-method.json` with `pipelex.catalog.not_found`, before replying. Nothing was spent. -A linkage id the plane does not know refuses the run, and on a run that sent a folder beside the id, that location is the discriminator rather than a coincidence: a rejected payload or a refused execution locus locates at `method_dir`, or at `files` when the files were listed, so only the unknown-method arm lands at `method_id`, and its hint says the id is not visible to the API key's organization. The catalog is org-scoped, so a link made with another organization's key, or against another plane, reads exactly like a deleted method. +A linkage id the plane does not know refuses the run, and on a run that sent a folder beside the id, the problem's `code` is the discriminator rather than its wording: a rejected payload or a refused execution locus answers with a code of its own, located at `method_dir`, or at `files` when the files were listed, so only the unknown method answers `pipelex.catalog.not_found`, its `params` naming the id the API key's organization does not hold. The catalog is org-scoped, so a link made with another organization's key, or against another plane, reads exactly like a deleted method. Report it with the `api_host` the link file records — that is what makes it diagnosable — and offer the same run **without** the id: it runs the very same bundle and loses only the history filing. Do not go looking for the bundle; the bundle was never in question. diff --git a/pipelex-codex/skills/pipelex-run/references/published-address.md b/pipelex-codex/skills/pipelex-run/references/published-address.md index 61555c65..68ebef69 100644 --- a/pipelex-codex/skills/pipelex-run/references/published-address.md +++ b/pipelex-codex/skills/pipelex-run/references/published-address.md @@ -4,7 +4,7 @@ Read this at step 1 when the target is a published method's address, passed as ` ## It pairs with nothing -An address is a complete run source, so **an address pairs with nothing**: a `method_dir`, `files` or a `method_id` beside it is refused with an `input_domain` error before anything runs. Every call carries the `method_ref` alone. +An address is a complete run source, so **an address pairs with nothing**: a `method_dir`, `files` or a `method_id` beside it is refused as `client.argument_invalid` before anything runs. Every call carries the `method_ref` alone. ## It floats without a tag diff --git a/pipelex-codex/skills/pipelex-synthetic-inputs/references/photograph.md b/pipelex-codex/skills/pipelex-synthetic-inputs/references/photograph.md index 0d8d64e2..09ff5219 100644 --- a/pipelex-codex/skills/pipelex-synthetic-inputs/references/photograph.md +++ b/pipelex-codex/skills/pipelex-synthetic-inputs/references/photograph.md @@ -58,7 +58,7 @@ Its description says what changes (the side, the angle, the damage) and repeats **A room seen from two places keeps its materials and loses its walls.** The model draws what the description puts on the left and the right of the frame, but as a view straight down the room, wherever the photographer was said to stand. A second view "from the opposite corner", with the windows on its left and the fireplace on its right, therefore puts the two on facing walls, when the first photograph had them side by side. Write the room's plan before the first description, naming what is on each wall, and describe the second view by the wall it faces and what stands on the walls to its left and right: "facing the fireplace wall, the two windows on the right-hand wall, a bare wall on the left". -Follow each run with `mthds_run_status` at the hint it gives, then `mthds_run_results` once it is terminal. A failed run is reported with its `failure_message` verbatim, and that photograph is left without a path; do not retry it with a reworded description on a guess. +Follow each run with `mthds_run_status` at the hint it gives, then `mthds_run_results` once it is terminal. A failed run is reported with its problem, `run_error` (`error` on the status), verbatim, and that photograph is left without a path; do not retry it with a reworded description on a guess. ## 3. Save it diff --git a/pipelex-codex/skills/shared/credentials.md b/pipelex-codex/skills/shared/credentials.md index 303ee9a3..e5896b4c 100644 --- a/pipelex-codex/skills/shared/credentials.md +++ b/pipelex-codex/skills/shared/credentials.md @@ -1,6 +1,6 @@ # Connecting the Pipelex workshop, and its key -Read this when an MCP-backed skill sends you here: because one of the plugin's `mthds_*` tools is absent from the session, or because a call returned a `config`-class error about the API key. It says what to tell the user on Codex, and nothing more: whether the skill stops there or carries on without the tool is the skill's own rule, which this file changes in neither direction. +Read this when an MCP-backed skill sends you here: because one of the plugin's `mthds_*` tools is absent from the session, or because a call returned a problem about the API key, `auth.missing_credential`, `auth.invalid_credential` or `auth.credential_expired`. It says what to tell the user on Codex, and nothing more: whether the skill stops there or carries on without the tool is the skill's own rule, which this file changes in neither direction. ## The tool is absent @@ -12,6 +12,8 @@ The Pipelex connector's `pipelex_*` tools, when the session has them, belong to The server authenticates to the API with **`PIPELEX_API_KEY`**. It uses the key its host hands it, which on Codex is a `PIPELEX_API_KEY` exported in the shell Codex starts from, forwarded by name. When the host hands it none, it reads the key saved in `~/.pipelex/.env`, or in the `.env` of `PIPELEX_HOME` when that variable reaches it, afresh on every call, so a key saved while the session runs is used from the next call with no restart. -So a `config`-class error about the key is answered by the workshop's login, which the user runs themselves in a terminal: **`npx -y @pipelex/mcp@latest login`** opens the browser on app.pipelex.com, mints a key for the account's current organization and saves it in that file (`--paste` reads one created in the app instead, for a machine with no browser). The pipelex CLI's `pipelex login` saves to the same file, so a key it saved counts too. When the error's hint says the host's own key was refused, the saved one is never consulted until that key is removed or replaced in the shell Codex starts from. Never read that file or print a key yourself. +So a problem about the key is answered by the workshop's login, which the user runs themselves in a terminal: **`npx -y @pipelex/mcp@latest login`** opens the browser on app.pipelex.com, mints a key for the account's current organization and saves it in that file (`--paste` reads one created in the app instead, for a machine with no browser). The pipelex CLI's `pipelex login` saves to the same file, so a key it saved counts too. When the tool's summary says the host's own key was refused, the saved one is never consulted until that key is removed or replaced in the shell Codex starts from. Never read that file or print a key yourself. The plugin's validation hook reads `PIPELEX_API_KEY` from Codex's environment alone, never from that file, so with only a saved key it still lints and formats each edit but skips validating it against the API. + +`auth.forbidden` is not about the key: the platform refused the action for the role the key's owner holds in the organization, and its `detail` names that role and what the action needs. No login or new key changes a role, so relay it as it came and never send the user to the login for it. diff --git a/pipelex-codex/skills/shared/writing-mthds.md b/pipelex-codex/skills/shared/writing-mthds.md index 0908d577..308265d5 100644 --- a/pipelex-codex/skills/shared/writing-mthds.md +++ b/pipelex-codex/skills/shared/writing-mthds.md @@ -704,7 +704,7 @@ A dry run composes the document for real against mock inputs, which checks the t **The catalog stores no template file yet**: `mthds_save_method` takes `.mthds` and `.py` files alone, so a saved method whose step names a template file does not load by its id, while its directory still validates and runs as `method_dir`. -**A `template_check_warning` in a valid verdict's `warnings`** is the template check's finding in the file a step names, located by its `pipe_code`, `template_file` and `template_location`, such as a field that matches no input of the step. It never changes `is_valid`, but the printed file may show it. A skill that writes the method fixes it in the template it wrote, or in the step, and validates again; a template the user supplied is theirs, so name the finding and ask before changing it. A skill that only reads or runs the method reports it with the verdict. +**A `pipelex.docgen.template_warning` in a valid verdict's `warnings`** is the template check's finding in the file a step names, a problem item located at the step's pipe (`location.pipe`) whose `params` carry `template_file`, the file as the step names it, and `template_location`, where in the file, such as a field that matches no input of the step. It never changes `is_valid`, but the printed file may show it. A skill that writes the method fixes it in the template it wrote, or in the step, and validates again; a template the user supplied is theirs, so name the finding and ask before changing it. A skill that only reads or runs the method reports it with the verdict. ### PipeFunc — call a Python function of the method's folder diff --git a/pipelex-vibe/skills/pipelex-catalog/SKILL.md b/pipelex-vibe/skills/pipelex-catalog/SKILL.md index ffd4e3c1..ebec493b 100644 --- a/pipelex-vibe/skills/pipelex-catalog/SKILL.md +++ b/pipelex-vibe/skills/pipelex-catalog/SKILL.md @@ -11,7 +11,7 @@ Every gesture between a bundle directory and the organization's catalog: [list a - **`mthds_list_methods`**, **`mthds_save_method`**, **`mthds_publish_method`** and **`mthds_get_method`** are required, with no fallback. - **If the catalog tools are absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Mistral Vibe. Never report a method id, a name, a version, or a method as saved or published when the answer did not come from these tools. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. ## Guards @@ -57,10 +57,10 @@ The target is a bundle directory. | a templated bundle answers `is_valid: false`, its template *not supplied with its bundle* | expected, as step 4 says: the draft runs only from its directory and cannot be published to run by id. **Never route it to editing** | | a save or a publish answers `is_valid: false` | a **produced verdict**, not an error: the save stored the draft anyway, and the publish published nothing. Report `validation_errors[]`; route a contract-preserving fix to `/pipelex:pipelex-edit`, a structural one to `/pipelex:pipelex-design` | | the bundle is valid with pending signatures | A **valid bundle with pending signatures is saved**, as a draft: say plainly that the method does not run yet, and which signatures are still open | -| `input_domain` at `expected_updated_at`: the draft moved since this directory synced, or it holds a pulled version | nothing was written. Read [conflict.md](references/conflict.md) before replying: unless it finds this session's own save, give the user the timestamps and the ways forward it describes. **Never choose between them.** | -| `input_domain` at `expected_draft_updated_at` | nothing was published: the draft moved since it was seen. Publish only once the user has seen it, saved or pulled, **never under the token the refusal names** | -| `input_domain` at `method_id` | read [unknown-id.md](references/unknown-id.md) before concluding anything: several faults land there. A dead link is removed only on the user's yes, the one thing this skill ever takes off disk | -| a create fails on a timeout or a transport fault | **does not retry.** A create carries no idempotency key yet, so a retry mints a second method: list the catalog first and see whether the first one landed | +| a problem at `expected_updated_at`: the draft moved since this directory synced, or it holds a pulled version | nothing was written. Read [conflict.md](references/conflict.md) before replying: unless it finds this session's own save, give the user the timestamps and the ways forward it describes. **Never choose between them.** | +| a problem at `expected_draft_updated_at` | nothing was published: the draft moved since it was seen. Publish only once the user has seen it, saved or pulled, **never under the token the refusal names** | +| `pipelex.catalog.not_found`, or a problem at `method_id` | read [unknown-id.md](references/unknown-id.md) before concluding anything: its `code` tells the faults apart. A dead link is removed only on the user's yes, the one thing this skill ever takes off disk | +| a create answers `client.outcome_unknown` | **does not retry.** A retry mints a second method: list the catalog first and see whether the first one landed | | the pull's directory holds a bundle of its own, or a link naming another method | somebody else's work: pull into another directory | | the pull's directory is linked to this method, files identical | only the link's `synced_updated_at` was refreshed: say the directory was already up to date | | linked, files differ, the saved method has **not** moved | the difference is local work this directory never saved: offer to [save](#save) it, or to pull into a new sibling directory to compare | @@ -72,4 +72,4 @@ The target is a bundle directory. - [python.md](references/python.md): the bundle holds a `PipeFunc`, before choosing `python`. - [link-file.md](references/link-file.md): a save's `link_file` came back `written: false`. - [conflict.md](references/conflict.md): a save refused at `expected_updated_at`, or a restore. -- [unknown-id.md](references/unknown-id.md): an `input_domain` error at `method_id`. +- [unknown-id.md](references/unknown-id.md): a miss, or a problem at `method_id`. diff --git a/pipelex-vibe/skills/pipelex-catalog/references/conflict.md b/pipelex-vibe/skills/pipelex-catalog/references/conflict.md index fb2a1c31..47aed0e5 100644 --- a/pipelex-vibe/skills/pipelex-catalog/references/conflict.md +++ b/pipelex-vibe/skills/pipelex-catalog/references/conflict.md @@ -1,6 +1,6 @@ # When a save is refused at `expected_updated_at`, or a version is restored -Read this when `mthds_save_method` answers an `input_domain` error at `expected_updated_at`, or before saving a directory that holds a pulled version because the user asked to restore it, before replying to the user. A refusal writes nothing, not the draft and not the link. A conflict names the draft's current `updated_at` and the token the save was sent under; a save refused because the directory holds a pulled version names the token a restore takes. Only the draft is at stake: published versions never change, and nothing below publishes. +Read this when `mthds_save_method` answers a problem at `expected_updated_at`, or before saving a directory that holds a pulled version because the user asked to restore it, before replying to the user. A refusal writes nothing, not the draft and not the link. A conflict is `pipelex.catalog.update_conflict`, whose `message` names the draft's current `updated_at` and the token the save was sent under; a save refused because the directory holds a pulled version is `client.argument_invalid` with `params.reason` `version_pulled`, whose `message` names the token a restore takes. Only the draft is at stake: published versions never change, and nothing below publishes. **First, does the directory hold a pulled version?** When `pipelex-method.json` records a `synced_version`, or the refusal says the directory holds one, the files here are version n, pulled to read or to start over from, perhaps edited since, and saving them replaces the draft with them: a restore. Unless the user asked for it, say so and give the two ways forward: pull the draft back into this directory to go on working on the draft, or restore, which makes these files, edits included, the draft. The pull writes over the version's untouched files freely, since the catalog stores them, and refuses a file edited since the version pull: those edits survive only a restore or a copy the user moves aside first, so never answer that refusal with `overwrite: true` without saying the edits are lost. A restore, made only on the user's request or an explicit yes, is the same call with `expected_updated_at` set to the `updated_at` the version pull reported, which the link records as `synced_updated_at` and the refusal names too, and `python` as the version's `.py` files, or `[]` when it has none, since an omitted `python` keeps the draft's. That token is the draft as the pull found it, so a draft saved since then refuses the restore: that refusal is a conflict, answered as the last paragraph and its two ways forward say, and saving over it is this restore sent with the draft's current `updated_at`, on the user's yes once they have seen both timestamps. Never take the draft's current `updated_at` for a restore before that refusal, from a pull or from anywhere else: it would restore over a draft nobody here has seen. A restore publishes nothing; a publish of the restored draft is a request of its own. diff --git a/pipelex-vibe/skills/pipelex-catalog/references/unknown-id.md b/pipelex-vibe/skills/pipelex-catalog/references/unknown-id.md index 2dd255c2..80112b26 100644 --- a/pipelex-vibe/skills/pipelex-catalog/references/unknown-id.md +++ b/pipelex-vibe/skills/pipelex-catalog/references/unknown-id.md @@ -1,15 +1,19 @@ -# An error at `method_id` +# A miss, or a problem at `method_id` -Read this when `mthds_save_method`, `mthds_publish_method` or a pull's `mthds_get_method` answers an `input_domain` error at `method_id`, before concluding anything about the directory's link. The skill's guard on the link holds throughout: it is removed only on the user's yes. +Read this when `mthds_save_method`, `mthds_publish_method` or a pull's `mthds_get_method` answers `pipelex.catalog.not_found`, or another problem located at `method_id`, before concluding anything about the directory's link. The skill's guard on the link holds throughout: it is removed only on the user's yes. -An unknown `method_id` comes back at that location, and so do several other faults: a payload the platform rejected, an organization-context failure, and the workshop's own refusal when this directory's link names a *different* method from the id being saved. **The location alone never tells them apart**, so read the message and the hint before doing anything: only the not-found answer names `pipelex-method.json` and the `api_host` and explains that the catalog is org-scoped, so a method from another organization reads exactly like a miss. Anything else is a different fault: the link is not dead, it stays where it is, and the fix is to the call. +Several faults land on the same id, and **the problem's `code` tells them apart**, never its location or its wording. Only `pipelex.catalog.not_found` whose `params.resource` is `method` is a miss: the catalog is org-scoped, so a method from another organization reads exactly like one. Anything else is a different fault, the link is not dead, it stays where it is, and the fix is to the call: -**A version suffix is refused there too, and is not a miss.** A save and a publish take the bare id, since both act on the draft, so `mt_…@` is refused before anything is sent: call again with the bare id, and to publish an old version's content again, pull that version, restore it as the draft and publish that. A pull of a version the method never had names the versions it has: offer one of those, or the draft. +- `client.target_exists` at `method_id` is the workshop's own refusal when this directory's link names a *different* method from the id being saved. Its `message` names both and what to pass instead. +- `client.argument_invalid` at `method_id` is a call the workshop refused before sending it, its `params.reason` saying why. **A version suffix is refused there, as `version_suffix`, and is not a miss.** A save and a publish take the bare id, since both act on the draft, so `mt_…@` is refused before anything is sent: call again with the bare id, and to publish an old version's content again, pull that version, restore it as the draft and publish that. +- `pipelex.catalog.not_found` whose `params.resource` is `version` is a pull of a version the method never had. Its `message` names the versions it has: offer one of those, or the draft. +- `method.package_invalid` with `params.reason` `empty_tree` is a pull of a method whose stored source holds no file yet. It is not a miss: relay it as the pull's report step says. +- Any other code, such as a payload the platform rejected or a failure of the organization's context, is relayed with its `detail` and `next_step`. -**A save's miss is checked against a read first.** When a save answers that the id is not visible, call `mthds_get_method` on the same bare id without `output_dir`: when it reads the method, the id is alive and this platform has no draft save yet, a platform older than drafts. Say so and stop; the link stays and nothing here creates a method. +**A save's miss is checked against a read first.** When a save answers `pipelex.catalog.not_found`, call `mthds_get_method` on the same bare id without `output_dir`: when it reads the method, the id is alive and this platform has no draft save yet, a platform older than drafts. Say so and stop; the link stays and nothing here creates a method. -When the hint does say the id is not visible, and a read does not find it either, report it **with the `api_host` the link file records** — that is what makes it diagnosable: the link was made against another plane, or with another organization's key. +When a read does not find it either, report the miss **with the `api_host` the link file records** — that is what makes it diagnosable: the link was made against another plane, or with another organization's key. Then offer to save the directory as a **new** method. That needs the stale link gone first: the workshop refuses a create into a directory another link claims, rather than minting a duplicate nobody can delete. So ask, and on a yes remove `pipelex-method.json` and run the create, which writes a fresh link. -**A pull or a publish has no link to judge.** When the error came from `mthds_get_method` or `mthds_publish_method`, nothing was written or published and nothing on disk is touched. An empty stored source answers at the same location and is not a miss: relay it as the pull's report step says. Otherwise relay the answer and its hint, and when the hint says the id is not visible, say that a method saved from another organization, or on another plane, reads exactly like a miss, and offer to find the method by name, as the skill's "List and find" says. +**A pull or a publish has no link to judge.** When the problem came from `mthds_get_method` or `mthds_publish_method`, nothing was written or published and nothing on disk is touched. Relay its `detail` and `next_step`, and on a miss say that a method saved from another organization, or on another plane, reads exactly like one, and offer to find the method by name, as the skill's "List and find" says. diff --git a/pipelex-vibe/skills/pipelex-design/SKILL.md b/pipelex-vibe/skills/pipelex-design/SKILL.md index 93f2b937..ac2be189 100644 --- a/pipelex-vibe/skills/pipelex-design/SKILL.md +++ b/pipelex-vibe/skills/pipelex-design/SKILL.md @@ -11,7 +11,7 @@ Design a `.mthds` method **contract-first**, directly or stepwise (step 3). A st - **`mthds_validate`** and **`mthds_inputs_template`** are required: this skill never guesses at validity. - **If the tools are absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Mistral Vibe. Do not write `.mthds` files without validation available. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never silently skip validation. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never silently skip validation. ## Guards @@ -52,7 +52,7 @@ Design the whole graph in memory, then write `main.mthds` in the bundle home, to Call `mthds_validate`. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. -Branch on the **structured verdict**, never on transport: `is_valid: true` is complete with `is_runnable: true` and nothing pending, and otherwise a scaffold whose backlog is the summary's `## Pending signatures`; on `is_valid: false`, fix from `validation_errors[]` and the summary's locators, then re-validate. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `template_check_warning`. +Branch on the **structured verdict**, never on transport: `is_valid: true` is complete with `is_runnable: true` and nothing pending, and otherwise a scaffold whose backlog is the summary's `## Pending signatures`; on `is_valid: false`, fix from `errors[]`, then re-validate. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `pipelex.docgen.template_warning`. ### 6. The runnable gate and delivery @@ -65,7 +65,7 @@ For a completed method, validate once more and confirm **`is_valid: true`, `is_r 5. **Hand off**: `/pipelex:pipelex-inputs` prepares the user's files, or test files with planted facts, then `/pipelex:pipelex-run` runs the method, and `/pipelex:pipelex-lab` writes answer keys and scores the runs; `/pipelex:pipelex-catalog` saves it under an `mt_…` id; `/pipelex:pipelex-integrate` wires it into a codebase (a `package.json` or a `pyproject.toml`), and with neither, `/pipelex:pipelex-scaffold` creates an app around it. 6. Search the whole project for `sources.json` files carrying `"generator": "pipelex-integrate"` — `grep -rl '"pipelex-integrate"' --include=sources.json .` — which sit beside each generated tree, never beside the bundle. Keep each one whose `sources` name a `.mthds` file this change rewrote, moved or removed, or whose `templates` name a template file it changed, **or whose `bundle_dir` holds a `.mthds` file this change created** — a new file is in no `sources` map, yet the call site loads every `.mthds` file under that directory. For each, say the generated types in that directory are now stale and offer `/pipelex:pipelex-integrate` to refresh them: it regenerates in place and touches the call site only if the types no longer fit it. -**Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex:pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex:pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a `config`-class error included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. +**Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex:pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex:pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a problem in the `account` domain included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. ## Re-entry @@ -77,8 +77,8 @@ For a completed method, validate once more and confirm **`is_valid: true`, `is_r | Condition | Do this | |---|---| -| `status: "error"`, class `input_domain` | fix the call | -| `status: "error"`, class `runtime` | report it, and retry once before stopping | +| `status: "error"`, `domain: "input"` | fix the call | +| any other `status: "error"` | report it, after one retry when its `retry` is `"yes"` | | validation fails twice on the same construct, or the client contract itself looks wrong | pause and show the user | ## References diff --git a/pipelex-vibe/skills/pipelex-design/references/stepwise.md b/pipelex-vibe/skills/pipelex-design/references/stepwise.md index 9604046c..b604c77a 100644 --- a/pipelex-vibe/skills/pipelex-design/references/stepwise.md +++ b/pipelex-vibe/skills/pipelex-design/references/stepwise.md @@ -48,7 +48,7 @@ Given pending signature `S` with frozen `inputs`, `output`, `description`, and ` The new file bounds the ordinary fix: - **Contract mismatch:** conform the definition to the frozen header. If the header itself is wrong, that is a propagating contract change; pause and revise the parent region deliberately rather than silently changing the header. -- **Other semantic errors:** use `validation_errors[]`, the Markdown locators, and the relevant section of the authoring reference; fix the added file and re-validate. +- **Other semantic errors:** use the verdict's `errors[]`, each item's `code`, `detail` and `location`, and the relevant section of the authoring reference; fix the added file and re-validate. ## Stopping early diff --git a/pipelex-vibe/skills/pipelex-edit/SKILL.md b/pipelex-vibe/skills/pipelex-edit/SKILL.md index 9c6d0f57..fc55bd87 100644 --- a/pipelex-vibe/skills/pipelex-edit/SKILL.md +++ b/pipelex-vibe/skills/pipelex-edit/SKILL.md @@ -14,7 +14,7 @@ Modify an existing MTHDS method bundle. There are two classes of change; this sk - **`mthds_validate`** is required: it proves every edit. **Never declare an edit done on the hook's silence alone**: its semantic stage is skipped without an API key. - **If the tool is absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Mistral Vibe. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. - **`mthds_inputs_template`** is needed only by Step 6, when the edit could have touched the input template. **`mthds_models`** serves a model change in Step 4, and its absence is no stop: the model references say what to do without it. ## Mode Selection @@ -46,7 +46,7 @@ Check the requested change against the scope split at the top. Structural or con Validate the whole bundle **before editing**: call `mthds_validate` on the bundle directory, and branch on the structured verdict, never on transport. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. - `is_valid: true` → record whether it is runnable or a scaffold (non-empty `pending_signatures`). That same state must hold after your edits. -- `is_valid: false` → the bundle is broken **before** your change: surface the `validation_errors[]` and the Markdown summary, and offer to repair first. **Never edit on a broken baseline.** +- `is_valid: false` → the bundle is broken **before** your change: surface the `errors[]` and the Markdown summary, and offer to repair first. **Never edit on a broken baseline.** ### Step 4: Apply the edits @@ -60,7 +60,7 @@ Before editing a construct you have not touched recently, read [the MTHDS refere ### Step 5: Re-validate -Same whole-bundle `mthds_validate` call as Step 3. The bar is the **baseline verdict restored**: `is_valid: true`, and the runnable or scaffold state unchanged (a renamed pending signature renames its backlog entry; nothing else in the pending set moves). **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `template_check_warning`. On `is_valid: false` the failure is in your edit: use the summary's locators, fix, re-validate. On `status: "error"` the edit is applied but **unproven** — never report it as done: tell the user it is on disk but could not be validated, and offer to restore the pre-edit content you still hold from Step 1, or to retry once the server is reachable again. +Same whole-bundle `mthds_validate` call as Step 3. The bar is the **baseline verdict restored**: `is_valid: true`, and the runnable or scaffold state unchanged (a renamed pending signature renames its backlog entry; nothing else in the pending set moves). **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `pipelex.docgen.template_warning`. On `is_valid: false` the failure is in your edit: use the summary's locators, fix, re-validate. On `status: "error"` the edit is applied but **unproven** — never report it as done: tell the user it is on disk but could not be validated, and offer to restore the pre-edit content you still hold from Step 1, or to retry once the server is reachable again. ### Step 6: Inputs refresh check @@ -72,14 +72,14 @@ State what changed (files and constructs), give the verdict line from the summar **Generated types may now be stale.** Search the whole project for `sources.json` files carrying `"generator": "pipelex-integrate"` — `grep -rl '"pipelex-integrate"' --include=sources.json .` — which sit beside each generated tree, never beside the bundle. Keep each one whose `sources` name a `.mthds` file this change rewrote, moved or removed, or whose `templates` name a template file it changed, **or whose `bundle_dir` holds a `.mthds` file this change created** — a new file is in no `sources` map, yet the call site loads every `.mthds` file under that directory. For each, say the generated types in that directory are now stale and offer `/pipelex:pipelex-integrate` to refresh them: it regenerates in place and touches the call site only if the types no longer fit it. -**Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex:pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex:pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a `config`-class error included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. +**Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex:pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex:pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a problem in the `account` domain included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. ## Stops | Condition | Do this | |---|---| -| `status: "error"`, class `input_domain` | fix the call | -| `status: "error"`, class `runtime` | report it, and retry once before stopping | +| `status: "error"`, `domain: "input"` | fix the call | +| any other `status: "error"` | report it, after one retry when its `retry` is `"yes"` | | the same construct fails twice after your edit | pause and show the user instead of thrashing | ## References diff --git a/pipelex-vibe/skills/pipelex-explain/SKILL.md b/pipelex-vibe/skills/pipelex-explain/SKILL.md index a469c933..968bde90 100644 --- a/pipelex-vibe/skills/pipelex-explain/SKILL.md +++ b/pipelex-vibe/skills/pipelex-explain/SKILL.md @@ -16,7 +16,7 @@ Read a method and say what it does, in plain language. Reading costs nothing and - **A bundle directory needs no tool at all**: it is explained from its source, and `mthds_validate`, when present, adds the verdict line. Never refuse to explain a local bundle because the workshop is not connected. - **A catalog id or a published address needs the workshop**, since nothing of it is on disk. Where `mthds_get_method` is absent while the other tools answer, an id is explained at contract level, as an address is, and the explanation says which reading it is: a narrower explanation, not a stop. - **If the workshop is absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Mistral Vibe. That stop is only for a target that lives on the platform — a bundle directory on disk is still explained from its source, with the verdict line left out. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Same scope: on a local bundle a `config` error costs the verdict line and nothing else — carry on and say it was not checked. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Same scope: on a local bundle such a problem costs the verdict line and nothing else — carry on and say it was not checked. ## Guards @@ -36,7 +36,7 @@ A `PipeSignature` is **pending only when no concrete pipe of the same code exist ### 3. The verdict, when the workshop is there -One `mthds_validate` call on the bundle directory. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. **From a folder, explain the `.mthds` files in `files_sent`, naming any you read that it leaves out.** **A single file goes as `files` instead**, its `{path}` and then those of the templates its steps name: its folder may hold other methods. The call adds two things to the explanation: the **verdict line** (whether it is valid, whether it is runnable, what is still pending) and, when the verdict carries a `main_pipe`, the **main pipe's typed signature**: its namespaced ref, each declared input with its concept and whether it is required, and the concept it produces. Into the method's directory the workshop also writes its flowchart as `method-graph.html`, rewritten on every validation, and reports it as `graph_page`. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `template_check_warning`. +One `mthds_validate` call on the bundle directory. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. **From a folder, explain the `.mthds` files in `files_sent`, naming any you read that it leaves out.** **A single file goes as `files` instead**, its `{path}` and then those of the templates its steps name: its folder may hold other methods. The call adds two things to the explanation: the **verdict line** (whether it is valid, whether it is runnable, what is still pending) and, when the verdict carries a `main_pipe`, the **main pipe's typed signature**: its namespaced ref, each declared input with its concept and whether it is required, and the concept it produces. Into the method's directory the workshop also writes its flowchart as `method-graph.html`, rewritten on every validation, and reports it as `graph_page`. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `pipelex.docgen.template_warning`. Without the tool, explain from the source and **say the verdict was not checked**. Your own reading of the source is not a guess: the pipe types, the concepts and step 2's backlog are yours to state, saying whose reading it is. But do not present a validation verdict, a typed signature or a pending list as the workshop's when the workshop did not answer, and do not guess at validity. **On a target that is not on disk there is no such fallback.** @@ -79,11 +79,11 @@ Output: final_output | the workshop is absent, on an id or an address | stop per the Requirements: there is nothing to read | | `mthds_get_method` is absent while the other tools answer | explain the id at contract level, say the source was not read, and name the cause [not-on-disk.md](references/not-on-disk.md) gives | | an id's source comes back `truncated` | name the files you could not read and say the explanation is partial. Never describe a withheld file's pipes as absent. | -| an id is refused at `method_id` | give the tool's answer: an unknown id and an empty stored source are different answers, and an empty one is somebody's draft, not a wrong id | -| a selector call answers a no-verdict error | report the error and its `hint` verbatim; hosted address and id resolution is not live everywhere yet | +| an id is refused | give the tool's answer: an unknown id (`pipelex.catalog.not_found`) and an empty stored source (`method.package_invalid`) are different answers, and an empty one is somebody's draft, not a wrong id | +| a selector call answers a no-verdict problem | report its `detail` and `next_step` verbatim; hosted address and id resolution is not live everywhere yet | | a **local bundle** does not validate | explain it anyway from the source, say what the verdict was, and route a fix to `/pipelex:pipelex-edit` or `/pipelex:pipelex-design` | -| a **catalog id** does not validate | explain it from the source read above with `validation_errors[]` beside it, and say the fix is not on this disk | -| a published **address** does not validate | report `validation_errors[]` and stop: there is no source to explain, and the fix is upstream | +| a **catalog id** does not validate | explain it from the source read above with its `errors[]` beside it, and say the fix is not on this disk | +| a published **address** does not validate | report its `errors[]` and stop: there is no source to explain, and the fix is upstream | | the verdict carries no `main_pipe` | say so, and which cause the tool's message points to: the method settles no entry pipe, the contract did not come back whole, or the workshop predates the field. Do not reconstruct a signature from the input template. | | the user wants the method changed, or a saved method's files on disk | route: `/pipelex:pipelex-edit` for a contract-preserving fix, `/pipelex:pipelex-design` for a structural one, `/pipelex:pipelex-catalog` to bring a saved method to disk | diff --git a/pipelex-vibe/skills/pipelex-explain/references/not-on-disk.md b/pipelex-vibe/skills/pipelex-explain/references/not-on-disk.md index d2c8a31a..39b19058 100644 --- a/pipelex-vibe/skills/pipelex-explain/references/not-on-disk.md +++ b/pipelex-vibe/skills/pipelex-explain/references/not-on-disk.md @@ -6,7 +6,7 @@ The two targets part company on ownership rather than convenience. **A catalog i ## A catalog id: read it in full -Call `mthds_get_method` with the `method_id`, as the skill's step 1 says. The `files` it returns are explained **exactly as a bundle on disk is**, through the skill's steps 1 to 5, with the returned contents standing in for the files you would have read. The verdict of step 3 is one `mthds_validate` call naming the content that was read: `mt_…@draft` when the result's `version` is `draft`, and `mt_…@` for version n. A platform that does not resolve versions yet refuses the suffix, with a hint saying that a bare id reads the draft there: validate the bare id then, which reads the same stored content on that platform, and say so. +Call `mthds_get_method` with the `method_id`, as the skill's step 1 says. The `files` it returns are explained **exactly as a bundle on disk is**, through the skill's steps 1 to 5, with the returned contents standing in for the files you would have read. The verdict of step 3 is one `mthds_validate` call naming the content that was read: `mt_…@draft` when the result's `version` is `draft`, and `mt_…@` for version n. A platform that does not resolve versions yet refuses the suffix, the problem's `message` saying that a bare id reads the draft there: validate the bare id then, which reads the same stored content on that platform, and say so. **A bare id reads the draft here and the latest published version everywhere else.** `mthds_get_method` reads a bare id's draft, which is what the next save replaces, while a validation, an inputs template or a run of the same bare id reads the latest published version, what the method's callers run. So never validate a draft's source under the bare id, and say which content the explanation is of. The result's `publish_state` says how the two stand: `draft_ahead` means callers of the bare id run version `latest_version`, which differs from what you explained, so say so and offer to explain `mt_…@`; `draft_unchanged` means they run what you explained; `never_published` means a bare id runs nothing yet. @@ -18,7 +18,7 @@ Three things about the returned set are worth knowing before you describe it: ## Without `mthds_get_method` -When the other tools answer and `mthds_get_method` does not, read the id at contract level exactly as an address is read below, with `method_id` as the selector, and say that the source was not read rather than implying there was none to read. A bare id there is the latest published version, and one never published is refused as `method_not_published`, whose draft `mt_…@draft` can be read instead; say which you read. **The cause is a local workshop that predates the tool**, which `npx -y @pipelex/mcp@latest` refreshes; say so. The Pipelex connector's `pipelex_*` tools, when the session has them too, belong to a different server with no tool of this name, so they neither cause this nor stand in for the workshop. +When the other tools answer and `mthds_get_method` does not, read the id at contract level exactly as an address is read below, with `method_id` as the selector, and say that the source was not read rather than implying there was none to read. A bare id there is the latest published version, and one never published is refused as `pipelex.catalog.not_published`, whose draft `mt_…@draft` can be read instead; say which you read. **The cause is a local workshop that predates the tool**, which `npx -y @pipelex/mcp@latest` refreshes; say so. The Pipelex connector's `pipelex_*` tools, when the session has them too, belong to a different server with no tool of this name, so they neither cause this nor stand in for the workshop. ## A published address: its contract @@ -31,5 +31,5 @@ When the other tools answer and `mthds_get_method` does not, read the id at cont A published address has no source to fall back on, and neither has an id read at contract level, so these verdicts are said rather than filled in. An id read in full still has its source. - **The verdict is positive but carries no `main_pipe`.** The method settles no entry pipe, the contract did not come back whole, or the workshop predates the field — the same three causes `/pipelex-integrate` names, and the one-line signature in the text summary is missing in all three. Say the verdict was positive and that it carries no signature to describe the contract with, and name which of the three the tool's own message points to. -- **The verdict is `is_valid: false`.** There is no `main_pipe` on an invalid verdict and `mthds_inputs_template` answers with `validation_errors[]` rather than shapes, so nothing about the method is readable **from the verdict** — though for an id read in full the source still is, and an invalid stored method is worth explaining from its source with the errors beside it. Report the errors as they came back. **Do not route a remote target to `/pipelex-edit` or `/pipelex-design`**: a stored method is fixed where it is edited — `/pipelex-catalog` is what brings it to disk first — and a published address is fixed in the repository it names. -- **The id is refused rather than read.** An unknown id and a method whose stored source is empty both arrive as `input_domain` at `method_id`: the first says no such method is visible to the API key's organization, which a method from another organization reads exactly like; the second says the row exists and holds no source yet. Give the one the tool gave, as the skill's stop table says. +- **The verdict is `is_valid: false`.** There is no `main_pipe` on an invalid verdict and `mthds_inputs_template` answers with `errors[]` rather than shapes, so nothing about the method is readable **from the verdict** — though for an id read in full the source still is, and an invalid stored method is worth explaining from its source with the errors beside it. Report the errors as they came back. **Do not route a remote target to `/pipelex-edit` or `/pipelex-design`**: a stored method is fixed where it is edited — `/pipelex-catalog` is what brings it to disk first — and a published address is fixed in the repository it names. +- **The id is refused rather than read.** An unknown id and a method whose stored source is empty are told apart by the problem's `code`: the first is `pipelex.catalog.not_found`, no such method visible to the API key's organization, which a method from another organization reads exactly like; the second is `method.package_invalid` at `method_id`, the row existing and holding no source yet. Give the one the tool gave, as the skill's stop table says. diff --git a/pipelex-vibe/skills/pipelex-inputs/SKILL.md b/pipelex-vibe/skills/pipelex-inputs/SKILL.md index 284cab7a..471aef6c 100644 --- a/pipelex-vibe/skills/pipelex-inputs/SKILL.md +++ b/pipelex-vibe/skills/pipelex-inputs/SKILL.md @@ -11,8 +11,8 @@ The one entry point for a method's inputs, through to run-ready inputs. - **`mthds_inputs_template`** is required: never hand-derive the template from the `.mthds` source. - **If the tool is absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Mistral Vibe. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never silently improvise a template. -- **`mthds_prepare_inputs`** is required at step 5, under the same two stops; never hand-fake a storage reference. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never silently improvise a template. +- **`mthds_prepare_inputs`** is required at step 5, under the same two stops, except `auth.forbidden` on a call with `kind` (see Stops); never hand-fake a storage reference. - **`mthds_list_methods`** and **`mthds_list_files`** are optional: without the first, ask for a saved method's `mt_…` id. ## Mode @@ -34,8 +34,8 @@ The one entry point for a method's inputs, through to run-ready inputs. The target takes three forms, one selector per call. - **A local bundle**, the usual case: `` is its directory, usually the one holding `main.mthds`, unless the caller names another. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. -- **A registered method**, an `mt_…` id with no local bundle in play, as `method_id`: bare, the latest published version; `@draft`, the draft; `@`, version n. **Say which one the template came from** (`method_version`) and offer the run on that same form; a bare id never published is refused as `method_not_published`, and `mt_…@draft` is then the target. `` is a directory the user names, by default a new `.//` without the suffix. -- **A published method**, as `method_ref: "github.com//[/][@]"`: read [references/published-address.md](references/published-address.md) before the first call. **An address with no tag is accepted, and it floats**: say so in one line, recommend the tag, and carry on. +- **A registered method**, an `mt_…` id with no local bundle in play, as `method_id`: bare, the latest published version; `@draft`, the draft; `@`, version n. **Say which one the template came from** (`method_version`) and offer the run on that same form; a bare id never published is refused as `pipelex.catalog.not_published`, and `mt_…@draft` is then the target. `` is a directory the user names, by default a new `.//` without the suffix. +- **A published method**, as `method_ref: "github.com//[/][@]"`: read [published-address.md](references/published-address.md) before the first call. **An address with no tag is accepted, and it floats**: say so in one line, recommend the tag, and carry on. ### 2. The template @@ -53,8 +53,8 @@ Evaluated in order: | No clear signal (e.g. right after `/pipelex:pipelex-design`, with no further context) | **Template**, then offer to populate | - **Template**: replace each file-ish mock URL (an `https://` URL on a `.invalid` host) with `""`, never `""`; save, show it with its path, and offer synthetic data or the user's files. -- **Synthetic**: read [references/synthetic.md](references/synthetic.md) before generating anything. **`pipelex-synthetic-inputs` is the file factory**, and makes every file input. Mistral Vibe has no cross-skill invocation, so open `../pipelex-synthetic-inputs/SKILL.md` and follow it. -- **User data**: read [references/user-data.md](references/user-data.md) before matching any file to an input. +- **Synthetic**: read [synthetic.md](references/synthetic.md) before generating anything. **`pipelex-synthetic-inputs` is the file factory**, and makes every file input. Mistral Vibe has no cross-skill invocation, so open `../pipelex-synthetic-inputs/SKILL.md` and follow it. +- **User data**: read [user-data.md](references/user-data.md) before matching any file to an input. - **Mixed**: the user's files first, then synthetic values for what they leave unfilled; read both references. - **The team's files**: read [team-files.md](../shared/team-files.md) before asking for a file, or for one named but not on disk. @@ -64,7 +64,7 @@ Fill the step 2 template in place, a composite native's fields included ([native ### 5. Prepare the inputs for a run -`mthds_prepare_inputs` uploads each local path, `data:` URL or inline bytes at a file input to Pipelex storage. Skip the call for the Template strategy. Otherwise, for a case's copies, **first delete any `inputs.prepared.json` an earlier prepare left in ``**, which a run would read after a prepare that writes none. Skip the call too **when every file-ish value is already an `http(s)` URL or a `pipelex-storage://` reference**: a run then reads `inputs.json`. +`mthds_prepare_inputs` uploads each local path, `data:` URL or inline bytes at a file input to Pipelex storage. Skip the call for the Template strategy. Otherwise, for a case's copies, **first delete any `inputs.prepared.json` an earlier prepare left in ``**. Skip the call too **when every file-ish value is already an `http(s)` URL or a `pipelex-storage://` reference**: a run then reads `inputs.json`. **Say what is about to leave the machine, before it does**: each file and where it goes (Pipelex storage, the user's organization, through their API key), or for a folder batch too long to list, the count and the folder; in interactive mode wait for a yes, in automatic mode state it and proceed. If the user declines, stop before the call and report that the inputs stay local and are not runnable. @@ -84,24 +84,25 @@ Say what is ready, or which placeholders are left. When a codebase here does not - no calling skill asked to stop at run-ready (a user who said not to run still gets the offer: an offer is not a run); - no placeholder remains; -- **every input the template asked for is filled** — one the factory could not make is absent, passes every other check and guarantees a failed run: say which input waits on the user, and why; +- **every input the template asked for is filled** — one the factory could not make is absent: say which input waits on the user, and why; - the inputs are run-ready: prepare succeeded, or step 5 skipped it because nothing needed uploading. -The offer names the file the run reads — `inputs.prepared.json` where prepare wrote one, else `inputs.json` — and the target: the bundle, the id or the address. +The offer names the file the run reads — `inputs.prepared.json` where prepare wrote one, else `inputs.json` — and the target. ## Stops | Condition | Do this | |---|---| -| template: `is_valid: false` | report `validation_errors[]` and the summary. A local bundle is repaired first (`/pipelex:pipelex-design` resumes it), then retried; a registered method through `/pipelex:pipelex-edit`, not here; a published one is reported as [its reference](references/published-address.md) says | -| template: `input_domain` | an unknown `pipe_ref` or unresolvable `main_pipe`: pass an explicit `pipe_ref`. At `method_dir`, `method_id` or `method_ref`, report it in the tool's words; another organization's id reads as a miss | -| `runtime`, either call | report, and retry once | +| template: `is_valid: false` | report `errors[]` and the summary. A local bundle is repaired first (`/pipelex:pipelex-design` resumes it), then retried; a registered method through `/pipelex:pipelex-edit`, not here; a published one is reported as [its reference](references/published-address.md) says | +| template: `request.pipe_not_found` or `request.pipe_ambiguous` | pass an explicit `pipe_ref`. Another `domain: "input"` problem: report it in the tool's words; another organization's id reads as a miss | +| `retry: "yes"`, either call | report, and retry once | | the factory returns no path | leave that one input unfilled, carry on with the others; report the reason and ask for the user's own file. Never fabricate a value or abandon `inputs.json` | -| prepare: `input_domain` at `inputs`, `pipe_ref`, `method_id` or `method_ref` | read [references/prepare-errors.md](references/prepare-errors.md) before replying or retrying; a storage size limit at `inputs` is terminal for this attempt | -| prepare, by address: `input_domain` at `files`, or `config` (the credential first, as the requirements say) | read [references/published-address.md](references/published-address.md) before naming a cause | +| prepare with `kind`: `auth.forbidden`, or a refusal naming `kind`, or `method_id` for `method_not_found`, `method_being_deleted` or `version_suffix` | read [synthetic.md](references/synthetic.md#test-files) before preparing again without `kind` | +| prepare: an `input` or `method` problem, not a refusal of `kind` | read [prepare-errors.md](references/prepare-errors.md) before replying or retrying; a storage size limit at `inputs` is terminal for this attempt | +| prepare, by address: refused at `files`, or an `account` problem | read [published-address.md](references/published-address.md) before naming a cause | ## References -- [synthetic.md](references/synthetic.md), [user-data.md](references/user-data.md): step 3, by strategy; both for Mixed. +- [synthetic.md](references/synthetic.md), [user-data.md](references/user-data.md): step 3, by strategy. - [published-address.md](references/published-address.md): a `method_ref` target. -- [prepare-errors.md](references/prepare-errors.md): prepare's `input_domain` errors. +- [prepare-errors.md](references/prepare-errors.md): prepare's input and method problems. diff --git a/pipelex-vibe/skills/pipelex-inputs/references/prepare-errors.md b/pipelex-vibe/skills/pipelex-inputs/references/prepare-errors.md index 11396395..d6f6919d 100644 --- a/pipelex-vibe/skills/pipelex-inputs/references/prepare-errors.md +++ b/pipelex-vibe/skills/pipelex-inputs/references/prepare-errors.md @@ -1,25 +1,27 @@ # When preparation fails -Read this when `mthds_prepare_inputs` answers `status: "error"` with class `input_domain` located at `inputs`, `pipe_ref`, `method_id` or `method_ref`, before replying to the user or retrying. Unlike `mthds_inputs_template`, the tool has no produced-invalid arm: it never returns a `validation_errors[]` list. **Read the error's `location` first**, because the causes need opposite repairs. The skill's file-fidelity guard holds throughout: nothing here is a reason to transform, derive or substitute a file, or to retry with one. +Read this when `mthds_prepare_inputs` answers `status: "error"` with a problem the inputs or the method's resolution must fix (its `domain` is `input` or `method`), before replying to the user or retrying. Unlike `mthds_inputs_template`, the tool has no produced-invalid arm: it never returns a verdict with `errors[]` of its own. **Read the problem's `code` first**, because the causes need opposite repairs; the location and the wording never tell them apart. A refusal of `kind` is not this file's: on a call that passed `kind: "test"`, `client.argument_invalid` whose `params.argument` is `kind`, or is `method_id` with `params.reason` `method_not_found`, `method_being_deleted` or `version_suffix`, and `auth.forbidden` are about recording test files, which the skill answers where it passes `kind`. The skill's file-fidelity guard holds throughout: nothing here is a reason to transform, derive or substitute a file, or to retry with one. -## `location: "inputs"` and the response reports a storage size limit +## `upload_too_large`: a file over the storage size limit -This is a terminal branch for the current preparation attempt. +The workshop refuses a file over the upload ceiling before anything is sent, as `client.argument_invalid` at `inputs` whose `params.reason` is `upload_too_large`. This is a terminal branch for the current preparation attempt. -1. Report the affected input and file; quote the tool's exact `message` and `hint` verbatim; and include the actual file size and the allowed limit whenever the response provides them, whether as fields or inside those diagnostics. +1. Report the affected input and file; quote the tool's exact `message` and `next_step` verbatim; and include the actual file size and the allowed limit whenever the response provides them, whether as fields or inside those diagnostics. 2. State explicitly that preparation failed, the inputs are not run-ready, and no run will be offered. 3. Make no follow-up file writes: preserve the user's original file, and a case's copy of it, unchanged, and write no `inputs.prepared.json` for a case (the skill's step 5 deleted any earlier one before the call) — nothing downstream then mistakes these inputs for run-ready, and `inputs.json` keeps its local-path form because step 5 writes the prepared values only on success. 4. Continue only after the user supplies a different acceptable input or reference, or the service limit changes. -## `location: "inputs"` and the response is not a size-limit failure +## A file the walk could not read or take -Surface the exact `message` and `hint`, then follow only the recovery they support. +Surface the exact `message` and `next_step`, then follow only the recovery they support. -- **For an unreadable local file**, verify that the same file exists, resolve its path to absolute as step 5 does, and retry preparation with the file bytes unchanged. A relative path sent as-is fails this way, as `Local file cannot be read: "inputs/cv.pdf" (ENOENT)`, because the workshop resolves it against its own working directory. The correction is to the request alone, and it must not rewrite the local relative path in `inputs.json`. -- **For any other asset failure**, retry only when the documented error policy explicitly permits a recovery that preserves the asset's content and identity. +- **For an unreadable local file**, `input.file_unreadable` naming the path, verify that the same file exists, resolve its path to absolute as step 5 does, and retry preparation with the file bytes unchanged. A relative path sent as-is fails this way, as `Local file cannot be read: "inputs/cv.pdf" (ENOENT)`, because the workshop resolves it against its own working directory. The correction is to the request alone, and it must not rewrite the local relative path in `inputs.json`. +- **For a value no file input takes**, `input.invalid` naming the input, such as a `data:` URL that does not decode, fix that value in the request from the user's own file or reference. +- **For any other asset failure**, retry only when the documented error policy explicitly permits a recovery that preserves the asset's content and identity: the problem's `retry` is `"yes"`, or its `next_step` names one. The method is not at fault, so don't revalidate it: `mthds_validate` and `mthds_inputs_template` only inspect the method definition, and they will keep answering "valid" while the same asset keeps failing. -## `location: "pipe_ref"`, `"method_id"` or `"method_ref"` +## The method or its pipe did not resolve + +`method.invalid` is a closure that does not load, its `errors` the closure's faults; `request.pipe_not_found` and `request.pipe_ambiguous` are an unknown `pipe_ref` or a method that settles no entry pipe or several, with the pipes the route suggests in its `params`; `pipelex.catalog.not_found` is an id the organization does not hold; and an address that did not resolve is the runner's own problem, located at `method_ref`. This is the arm whose diagnostics the tool delegates: get the structured errors from `mthds_validate` or `mthds_inputs_template`, repair, then retry. For an address the repair is not yours to make: report it with the address and the tag. -The closure did not resolve: an invalid bundle, an unknown `pipe_ref`, an unresolvable `main_pipe`, a method id with no stored source, or an address that did not resolve. This is the arm whose diagnostics the tool delegates: get the structured errors from `mthds_validate` or `mthds_inputs_template`, repair, then retry. For an address the repair is not yours to make: report it with the address and the tag. diff --git a/pipelex-vibe/skills/pipelex-inputs/references/published-address.md b/pipelex-vibe/skills/pipelex-inputs/references/published-address.md index d4081f83..a664b1ec 100644 --- a/pipelex-vibe/skills/pipelex-inputs/references/published-address.md +++ b/pipelex-vibe/skills/pipelex-inputs/references/published-address.md @@ -1,6 +1,6 @@ # A published address -Read this at step 1 when the target is a published method's address, passed as `method_ref`, before the first call; and again when `mthds_prepare_inputs` refuses the address in one of the two ways only an address meets. An address is passed exactly as a catalog id is, so every step runs as the skill says; what follows is where an address is genuinely not like an id. +Read this at step 1 when the target is a published method's address, passed as `method_ref`, before the first call; and again when `mthds_prepare_inputs` refuses the address, before naming a cause. An address is passed exactly as a catalog id is, so every step runs as the skill says; what follows is where an address is genuinely not like an id. ## Where the inputs go @@ -8,14 +8,14 @@ The server fetches the repository at the tag and locates the package there, so t ## A template that does not validate -When `mthds_inputs_template` answers `is_valid: false` on an address, the package at that address does not validate: report `validation_errors[]` with the address and its tag, and say the fix is upstream or another tag — never a local repair of source the user does not have. +When `mthds_inputs_template` answers `is_valid: false` on an address, the package at that address does not validate: report its `errors[]` with the address and its tag, and say the fix is upstream or another tag — never a local repair of source the user does not have. -## Prepare, `input_domain` at `files`: a workshop older than the selector +## Prepare refused at `files`: a workshop older than the selector -`mthds_prepare_inputs` took `files` and `method_id` alone until the release that gave it the address, so a workshop cached from before then does not know `method_ref` — and a host that validates a call against that older tool schema drops the argument before it is ever sent. The tell is the error itself: `input_domain` located at **`files`**, saying *"Provide MTHDS files or a method_id"*, on a call that did supply a selector — the message lists what the tool accepts and leaves `method_ref` out of it. Read it as a workshop that predates the selector, not as a missing target. The same address goes on templating normally throughout, because `mthds_inputs_template` has taken it for longer — which is what makes the pair of answers the diagnosis. +`mthds_prepare_inputs` took `files` and `method_id` alone until the release that gave it the address, so a workshop cached from before then does not know `method_ref` — and a host that validates a call against that older tool schema drops the argument before it is ever sent. The tell is the error itself: located at **`files`**, saying *"Provide MTHDS files or a method_id"*, on a call that did supply a selector — the message lists what the tool accepts and leaves `method_ref` out of it. Read it as a workshop that predates the selector, not as a missing target. The same address goes on templating normally throughout, because `mthds_inputs_template` has taken it for longer — which is what makes the pair of answers the diagnosis. Give the cure with both of its conditions: the launcher fetches the newest workshop only on its next spawn, so `npx -y @pipelex/mcp@latest` changes nothing until the host restarts the server and reloads its tool schema — and a refresh only reaches the selector once a published workshop carries `method_ref` on prepare at all. Where none does yet, say that this one leg is unavailable rather than leaving them refreshing in a loop, and never fall back to submitting files you do not have. -## Prepare, class `config`: the credential first, then the deployment +## Prepare, a problem in the `account` domain: the credential, and only the credential -The skill's `config` stop applies as written: surface the `hint` verbatim and deal with the credential first, since it is the one thing the user can act on. But a by-address target has one further cause here, and nothing in the answer yet tells you which of them you met. Preparation resolves an address's signature through the run route, which refuses a published package shipping in-process Python where the deployment hosts no sandbox — and that refusal arrives in this same `config` arm wearing the deployment's authentication wording. A template call that just succeeded on the same address rules nothing out, because preparation also uploads with the key and templating never exercises that. So once the key proves good, name the other cause rather than leaving the user with a mystery: a published package can be refused by the deployment itself, and one carrying no in-process Python is not affected. +The skill's account stop applies as written: relay the `next_step` verbatim and deal with the credential first, since it is the one thing the user can act on. A template call that just succeeded on the same address rules nothing out, because preparation also uploads with the key and templating never exercises that. What the problem names is the whole cause: preparation reads an address's signature from the package's `.mthds` files alone, so the deployment's refusal of a package shipping in-process Python never reaches it. That refusal, `pipelex.deployment.custom_code_requires_sandbox`, meets the run instead, which says so in its own words. diff --git a/pipelex-vibe/skills/pipelex-inputs/references/synthetic.md b/pipelex-vibe/skills/pipelex-inputs/references/synthetic.md index 7d679b3f..f42cd330 100644 --- a/pipelex-vibe/skills/pipelex-inputs/references/synthetic.md +++ b/pipelex-vibe/skills/pipelex-inputs/references/synthetic.md @@ -52,7 +52,7 @@ Step 5 uploads the factory's files as test files of the method, so the team's fi - **A published address, or an id with a suffix (`mt_…@draft`, `mt_…@`)**: leave `kind` out. An address names no saved method, and the workshop refuses a suffixed id beside `kind`, at `method_id`. The factory's files then go up as the organization's own files. - **Mixed, with the user's own files to upload as well**: `kind` applies to every upload of a call, and the user's files are theirs, not test files. Prepare in two calls: first the inputs holding the factory's files, alone, with `kind: "test"`; then every input, without `kind`, with those inputs' prepared values in place of their paths, which the second call passes through unchanged. Write the second call's `inputs` as step 5 says, and nothing when either call fails. -- **Refused over `kind`**, as `input_domain` at `kind`, or as a `config` error tagged `kind: "role"`: no file was recorded. The first means no saved method could be named, because the folder is linked to none, its link cannot be read, was made against another API or is still the older `pipelex-method.json`, or the platform no longer holds the method; the second means the user's role may not record test files, which is no problem with the key. Prepare again without `kind`, and say in one line that the factory's files went up as the organization's own and why, in the refusal's words, relaying its hint, such as saving the method so that its folder is linked, as the user's to act on, never yours. +- **Refused over `kind`**, as `client.argument_invalid` at `kind` or at `method_id` with `params.reason` `method_not_found`, `method_being_deleted` or `version_suffix`, or as `auth.forbidden`: no file was recorded. The first means no saved method could be named, its `params.reason` saying why: the folder is linked to none, its link cannot be read, was made against another API or is still the older `pipelex-method.json`; at `method_id`, its `params.argument` naming it, the platform no longer holds the method or is erasing it, or the id carries a suffix; the last means the user's role may not record test files, which is no problem with the key. Prepare again without `kind`, and say in one line that the factory's files went up as the organization's own and why, in the refusal's words, relaying its `message`, such as saving the method so that its folder is linked, as the user's to act on, never yours. Any other refusal at `method_id`, such as `not_a_catalog_id`, is a fault of the target that dropping `kind` does not cure: the skill's stop table routes it. - **No `kind` in the answer**: a workshop older than test files drops the argument, uploads the files as the organization's own and echoes no `kind`. The inputs are run-ready all the same, so do not prepare again: say in one line that `npx -y @pipelex/mcp@latest` refreshes the workshop once the host restarts the server and reloads its tools, and that the next preparation then records test files. When the answer carries `test_method_id`, step 5's report says the files went up as test files of that method. The report gives each generated file's temporary path, for a user who wants to open it before the run, and its name among the team's files, its file name, under which it is listed with the method. diff --git a/pipelex-vibe/skills/pipelex-integrate/SKILL.md b/pipelex-vibe/skills/pipelex-integrate/SKILL.md index 965e3c90..e418ecb8 100644 --- a/pipelex-vibe/skills/pipelex-integrate/SKILL.md +++ b/pipelex-vibe/skills/pipelex-integrate/SKILL.md @@ -12,7 +12,7 @@ Leave a project calling a method through one typed module, over generated types ## Requirements - **If a tool is absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Mistral Vibe. -- **If a call returns `status: "error"` with an error of class `config`**, STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. A **403** on `mthds_codegen` is a feature gate, not a key problem. +- **If a call returns a problem in the `account` domain, or `client.unreachable`**, STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. A **403** on `mthds_codegen` is a feature gate, not a key problem. - **`mthds_list_methods`** is optional, for a method named without its id; never stop for it. ## Guards @@ -75,7 +75,7 @@ Put the generated directory and the gate script step 10 copies in the formatter' - `status: "ok"`, `is_valid: true`, `output_dir` present → written; clean when `is_current: true` with an empty `orphans[]`. - **`orphans[]` non-empty and `drifts[]` empty** → carry on to step 7 and read [references/orphans.md](references/orphans.md). Read it off the two lists, never from `is_current`; `drifts[]` is present only when non-empty, so no `drifts` is the empty case. -- **`output_dir already holds …, which this tool does not own`** → that file is the user's: never delete, move or clear it, and never offer to; choose or ask for another directory, before the call too. +- **`client.target_exists`, a file this tool does not own** → that file is the user's: never delete, move or clear it, and never offer to; choose or ask for another directory, before the call too. - anything else (`drifts[]` included) → the stops. ### 7. The sidecar @@ -126,10 +126,10 @@ What was generated and where, the target and why, the call site's signature, the | Condition | Do this | |---|---| -| invalid, unrunnable, or `pending_signatures` | STOP, nothing generated: `validation_errors[]` to `/pipelex:pipelex-design` or `/pipelex:pipelex-edit`, else finish it in `/pipelex:pipelex-design` | -| `input_domain` at `method_ref` / `method_id` | report it in the tool's words | -| `runtime` | retry once (codegen: only if `retryable: true`, same `output_dir`), then report what landed | -| `input_domain` at `output_dir`, outside the server's directory | step 1's containment: STOP, relaunch, say what is already written | +| invalid, unrunnable, or `pending_signatures` | STOP, nothing generated: `errors[]` to `/pipelex:pipelex-design` or `/pipelex:pipelex-edit`, else finish it in `/pipelex:pipelex-design` | +| `domain: "input"` on `method_ref` / `method_id` | report it in the tool's words | +| `retry: "yes"`, or codegen's `client.write_failed` | retry once (codegen: same `output_dir`), then report what landed | +| `outside_workspace` at `output_dir` | step 1's containment: STOP, relaunch, say what is already written | | `is_current: false`, not step 6's orphans case | report `drifts[]` verbatim and stop; commit nothing | | no signature, by address or id | STOP as the fallback reference says; never guess the output concept | | `python-structures`, its `pipelex-sdk` after step 8 unread or below the floor, templated bundle | STOP, nothing generated: [python.md](references/python.md) | diff --git a/pipelex-vibe/skills/pipelex-lab/SKILL.md b/pipelex-vibe/skills/pipelex-lab/SKILL.md index 557a426f..7f6f558b 100644 --- a/pipelex-vibe/skills/pipelex-lab/SKILL.md +++ b/pipelex-vibe/skills/pipelex-lab/SKILL.md @@ -14,7 +14,7 @@ Start where the project stands: when `lab//` exists, read it and take up The loop needs the workshop: `/pipelex:pipelex-run` starts and follows each run, and this skill reads each result with **`mthds_run_results`**, and with `mthds_run_status` and `mthds_download_artifacts`. - **If those tools are absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Mistral Vibe. That stop comes at the loop: framing and setting up need no tool, so frame and set up, then stop before the loop. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. ## The lab directory diff --git a/pipelex-vibe/skills/pipelex-lab/references/log.md b/pipelex-vibe/skills/pipelex-lab/references/log.md index cee870fe..91d1e517 100644 --- a/pipelex-vibe/skills/pipelex-lab/references/log.md +++ b/pipelex-vibe/skills/pipelex-lab/references/log.md @@ -30,7 +30,7 @@ Failed: M3 (the memo puts the relocation clause below the medium items). Partial - **The duration** runs from the status's `created_at` to its `finished_at`. - **The score** is the Must and Must not lines passed, out of the case's Must and Must not lines. A reading an Also acceptable line allows passes the line it names, and planted facts are not scored. Partial and unscored lines count as not passed, toward the round's score and toward the pass bar, except a line the pass bar allows to be partial, which meets the bar when it is partial. - **A cut output** adds a line: "Output cut at the size cap: M4 and M6 unscored." -- **A failed run** is logged with the status and the first line of its `failure_message`, as `FAILED · …`, and scores nothing. +- **A failed run** is logged with the status and its problem's `code` and `title`, from `run_error` or the status's `error`, as `FAILED · …`, and scores nothing. - **An unfinished run** is logged as `UNFINISHED · still RUNNING after …`, with its run id, so that `/pipelex-run` can follow it later. ## A run the loop did not start diff --git a/pipelex-vibe/skills/pipelex-organize/SKILL.md b/pipelex-vibe/skills/pipelex-organize/SKILL.md index 7b87c2d1..7e392a82 100644 --- a/pipelex-vibe/skills/pipelex-organize/SKILL.md +++ b/pipelex-vibe/skills/pipelex-organize/SKILL.md @@ -13,7 +13,7 @@ It is a **content-preserving transformation**: the method's semantics never chan - **`mthds_validate`** is required: this skill never reorganizes without proving the verdict is preserved. - **If the tool is absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Mistral Vibe. Do not touch the bundle files without validation available. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never reorganize unvalidated. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never reorganize unvalidated. ## Guards @@ -62,14 +62,14 @@ One short summary: the layout, one line per file saying what it holds, and the p **When invoked on its own rather than by `/pipelex:pipelex-design`** (whose delivery step carries both notices), end with them, since an identical verdict still rewrote every file: 1. Search the whole project for `sources.json` files carrying `"generator": "pipelex-integrate"` — `grep -rl '"pipelex-integrate"' --include=sources.json .` — which sit beside each generated tree, never beside the bundle. Keep each one whose `sources` name a `.mthds` file this change rewrote, moved or removed, or whose `templates` name a template file it changed, **or whose `bundle_dir` holds a `.mthds` file this change created** — a new file is in no `sources` map, yet the call site loads every `.mthds` file under that directory. For each, say the generated types in that directory are now stale and offer `/pipelex:pipelex-integrate` to refresh them: it regenerates in place and touches the call site only if the types no longer fit it. -2. **Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex:pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex:pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a `config`-class error included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. +2. **Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex:pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex:pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a problem in the `account` domain included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. ## Stops | Condition | Do this | |---|---| | `is_valid: false` at the baseline | never reorganize a broken library: report the verdict and point to `/pipelex:pipelex-design` to fix it first | -| `status: "error"`, class `input_domain` | fix the call | -| `status: "error"`, class `runtime` | report it, and retry once before stopping | +| `status: "error"`, `domain: "input"` | fix the call | +| any other `status: "error"` | report it, after one retry when its `retry` is `"yes"` | | the candidate still differs from the baseline after two fixes of the composition | stop, leave the original layout untouched, and report the discrepancy | | the regrouping seems to need a semantic edit (a rename, a contract fix, a missing declaration) | stop and report it: that is `/pipelex:pipelex-design`'s work | diff --git a/pipelex-vibe/skills/pipelex-run/SKILL.md b/pipelex-vibe/skills/pipelex-run/SKILL.md index f3b8bc00..61831e7f 100644 --- a/pipelex-vibe/skills/pipelex-run/SKILL.md +++ b/pipelex-vibe/skills/pipelex-run/SKILL.md @@ -11,7 +11,7 @@ This skill owns the run lifecycle: Start a run from a target and its inputs, or - **`mthds_run`**, **`mthds_run_status`** and **`mthds_run_results`** are required, and to start a run **`mthds_validate`** and **`mthds_inputs_template`** too: they keep credit from being spent on a method or inputs that cannot work. - **If the run tools are absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Mistral Vibe. Never improvise a run id, a status or an output. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. - **`mthds_download_artifacts`**, **`mthds_list_methods`**, **`mthds_list_files`**: optional, never stop for one. ## Start a run @@ -26,7 +26,7 @@ The pipe is the declared main pipe unless the user named another: **carry its `p For a **bundle directory**, **first write a `.gitignore` holding `*` into each `runs/` in it that lacks one and whose folders hold `main_stuff.json`; add `*` to the `.gitignore` of each `inputs/` beside an `inputs.json`, and `/inputs.prepared.json` to the one beside that file, wherever the line is missing**, saying so, then one `mthds_validate` call on it. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. For an **`mt_…` id**, the same call with `method_id` in place of `method_dir`; for an address, `method_ref`. -The bar is `is_valid: true`, `is_runnable: true` and an empty `pending_signatures`. Short of it, report the verdict and route to `/pipelex:pipelex-design`, or to `/pipelex:pipelex-edit` when the fix is contract-preserving; an address's verdict is reported as [its reference](references/published-address.md) says. Never run a method that did not pass. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `template_check_warning`. +The bar is `is_valid: true`, `is_runnable: true` and an empty `pending_signatures`. Short of it, report the verdict and route to `/pipelex:pipelex-design`, or to `/pipelex:pipelex-edit` when the fix is contract-preserving; an address's verdict is reported as [its reference](references/published-address.md) says. Never run a method that did not pass. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `pipelex.docgen.template_warning`. **A dry run is this step, shown.** A run on test files is a real run. **When the verdict carries `graph_page.written: true`, give the page's `path` before the text flow**, for a browser to open. Pass on a new page's note that a project under git may want to ignore it. A `graph_page.error` gets one line, and the verdict stands. Show the flow as numbered text: each step, what it reads and makes, where it batches or branches, and which steps call a model. For an id or an address, give the contract from the verdict's `main_pipe` instead. Say that no model ran and nothing was spent. **Then end the turn there, even when the same request asked for the real run too**: the flow is the reply, and the paid run waits for the user's go. @@ -75,7 +75,7 @@ When the inputs came from a lab case and the lab did not start this run, offer ` ### 8. A failed run is reported, then routed, never bisected -Give `failure_message` **verbatim** first, then read [failed-run.md](references/failed-run.md) before routing it; route once, and stop. When the method holds a `PipeFunc`, name it as a suspect: **`PipeFunc` is experimental on the hosted plane.** Its Python runs in a sandbox with no network access, and the feature is still in development, so a method that validates can still fail when it runs. Per-pipe bisection is not this skill's. Do not re-run a failed method with altered inputs to see what happens — that spends credit on a guess. +Give the run's `run_error` **verbatim** first, then read [failed-run.md](references/failed-run.md) before routing it; route once, and stop. When the method holds a `PipeFunc`, name it as a suspect: **`PipeFunc` is experimental on the hosted plane.** Its Python runs in a sandbox with no network access, and the feature is still in development, so a method that validates can still fail when it runs. Per-pipe bisection is not this skill's. Do not re-run a failed method with altered inputs to see what happens — that spends credit on a guess. ## Follow a run @@ -91,7 +91,7 @@ An unknown run id is reported in the tool's own words. | Condition | Do this | |---|---| -| `mthds_run`: `input_domain` at `method_id`, on a linked run | nothing was spent: read [linked-run.md](references/linked-run.md) before replying | +| `mthds_run`: `pipelex.catalog.not_found`, on a linked run | nothing was spent: read [linked-run.md](references/linked-run.md) before replying | | `mthds_download_artifacts` absent | say nothing was saved to disk and report the stored references as they came back; the run still completed | | `mthds_download_artifacts` refuses a `dir` the user named | take step 7's ignore check, then call again without it, which saves into `runs//`, and say so. A refused `dir` is not a failed save | @@ -101,4 +101,4 @@ These references name a skill by its bare `/pipelex-`; to the user, write - [by-id.md](references/by-id.md), [published-address.md](references/published-address.md): an `mt_…` or a `method_ref` target, before the first call. - [failed-run.md](references/failed-run.md): a failed run, before routing it. -- [linked-run.md](references/linked-run.md): a linked run refused at `method_id`. +- [linked-run.md](references/linked-run.md): a linked run whose id is unknown. diff --git a/pipelex-vibe/skills/pipelex-run/references/by-id.md b/pipelex-vibe/skills/pipelex-run/references/by-id.md index fa25f1b2..7ea15209 100644 --- a/pipelex-vibe/skills/pipelex-run/references/by-id.md +++ b/pipelex-vibe/skills/pipelex-run/references/by-id.md @@ -16,15 +16,15 @@ When the user named no directory, its inputs are looked for under the bare id wh ## A method never published -A bare id of a method with no published version is refused at step 2 as `method_not_published`, and nothing is spent. Its only content is its draft: say so, carry `mt_…@draft` through every call from step 2 on, and name it in step 4's line, so the user sees that the draft is what runs. Publishing is `/pipelex-catalog`'s, on the user's request, and never a way to make a bare id run. +A bare id of a method with no published version is refused at step 2 as `pipelex.catalog.not_published`, and nothing is spent. Its only content is its draft: say so, carry `mt_…@draft` through every call from step 2 on, and name it in step 4's line, so the user sees that the draft is what runs. Publishing is `/pipelex-catalog`'s, on the user's request, and never a way to make a bare id run. ## A version the method never had -`mt_…@` for a version that does not exist is refused at `method_id` as `method_version_not_found`, and the message names the versions the method has. Nothing is spent: report it and ask which one to run. +`mt_…@` for a version that does not exist is refused as `pipelex.catalog.not_found` whose `params.resource` is `version`. Nothing is spent: report it in the tool's words and ask which one to run. ## A platform that does not resolve versions yet -Such a platform refuses `@draft` and `@`, and the hint says that a bare id reads the draft there. Report it in the tool's words; on that platform the bare id runs the draft. +Such a platform refuses `@draft` and `@`, and the problem's `message` says that a bare id reads the draft there. Report it in the tool's words; on that platform the bare id runs the draft. ## Which version ran diff --git a/pipelex-vibe/skills/pipelex-run/references/failed-run.md b/pipelex-vibe/skills/pipelex-run/references/failed-run.md index d35126b4..d5c50fb3 100644 --- a/pipelex-vibe/skills/pipelex-run/references/failed-run.md +++ b/pipelex-vibe/skills/pipelex-run/references/failed-run.md @@ -1,6 +1,10 @@ # A failed run -Read this at step 8 when a run failed, after giving its `failure_message` verbatim and before routing it. Route once, on what the failure says, and stop; the guards of the skill's step 8 hold throughout. +Read this at step 8 when a run failed, after giving its problem verbatim and before routing it. Route once, on what the failure says, and stop; the guards of the skill's step 8 hold throughout. + +The problem the run ended with is `run_error` on the failed state of `mthds_run_results`, `mthds_show_images` and `mthds_download_artifacts`, and `error` on `mthds_run_status`: its `code` (such as `run.timed_out`, `run.cancelled` or `model.unavailable`), its `domain` and `retry`, its `title`, `detail` and `next_step`, and its `errors`, the run's faults, of which `errors_omitted` counts those left out. The tool's summary renders it and closes with a support line, the run id, the code and the time the run ended: keep that line in the report, since it is what the people who run the platform find the run by. A run that stored no problem carries its status alone, and the summary says so. + +**Read the `domain` beside the wording.** `input` says the inputs must change and `method` that the method must; `runtime`, `account` and `operator` point away from both, at a provider, a quota, the organization's account or the platform, which is reported with its `next_step` rather than routed, unless the failure's own words match a row below. | What the failure says | Where it goes | |---|---| @@ -13,7 +17,7 @@ Read this at step 8 when a run failed, after giving its `failure_message` verbat A folder, like listed `files`, sends `.mthds` files and the templates their steps name, never a `.py` file, and a linked id fetches nothing: a caller-supplied source takes precedence over the stored method, which is read only when no folder or files were sent at all, so a linked run gains its history entry and nothing else, the stored `.py` files included. A bundle whose `PipeFunc` names a module of its own folder therefore has **no channel for its Python on any run of the directory**, linked or not. The path that carries it is `/pipelex-catalog`: a saved method run by its id alone has its `.mthds` and `.py` assembled into the run bundle server-side, the draft's as `mt_…@draft` and a version's once it is published. -So on a run of the directory the suspicion sharpens, but only when the failure says so. Where `failure_message` implicates finding or importing that function or its module, say that as the cause rather than offering it as one candidate among several, and give the cure: `/pipelex-catalog` saves the bundle with its Python as the method's draft, and `mt_…@draft`, run by its id alone, gets both. **Where it says anything else, route on what it says** — a missing input, a model or prompt fault, a failure upstream of the custom pipe — and leave the `PipeFunc` a suspect rather than promoting it: a bundle holding one is not evidence that it is what failed, and saving it with its Python cures nothing but that. +So on a run of the directory the suspicion sharpens, but only when the failure says so. Where the run's problem implicates finding or importing that function or its module, say that as the cause rather than offering it as one candidate among several, and give the cure: `/pipelex-catalog` saves the bundle with its Python as the method's draft, and `mt_…@draft`, run by its id alone, gets both. **Where it says anything else, route on what it says** — a missing input, a model or prompt fault, a failure upstream of the custom pipe — and leave the `PipeFunc` a suspect rather than promoting it: a bundle holding one is not evidence that it is what failed, and saving it with its Python cures nothing but that. ## A published address diff --git a/pipelex-vibe/skills/pipelex-run/references/linked-run.md b/pipelex-vibe/skills/pipelex-run/references/linked-run.md index eb68719f..35ccf212 100644 --- a/pipelex-vibe/skills/pipelex-run/references/linked-run.md +++ b/pipelex-vibe/skills/pipelex-run/references/linked-run.md @@ -1,7 +1,7 @@ -# A linked run refused at `method_id` +# A linked run whose id is unknown -Read this when `mthds_run` refuses a run that sent a linked directory as `method_dir` beside the `method_id` of its `pipelex-method.json` with an `input_domain` error located at `method_id`, before replying. Nothing was spent. +Read this when `mthds_run` refuses a run that sent a linked directory as `method_dir` beside the `method_id` of its `pipelex-method.json` with `pipelex.catalog.not_found`, before replying. Nothing was spent. -A linkage id the plane does not know refuses the run, and on a run that sent a folder beside the id, that location is the discriminator rather than a coincidence: a rejected payload or a refused execution locus locates at `method_dir`, or at `files` when the files were listed, so only the unknown-method arm lands at `method_id`, and its hint says the id is not visible to the API key's organization. The catalog is org-scoped, so a link made with another organization's key, or against another plane, reads exactly like a deleted method. +A linkage id the plane does not know refuses the run, and on a run that sent a folder beside the id, the problem's `code` is the discriminator rather than its wording: a rejected payload or a refused execution locus answers with a code of its own, located at `method_dir`, or at `files` when the files were listed, so only the unknown method answers `pipelex.catalog.not_found`, its `params` naming the id the API key's organization does not hold. The catalog is org-scoped, so a link made with another organization's key, or against another plane, reads exactly like a deleted method. Report it with the `api_host` the link file records — that is what makes it diagnosable — and offer the same run **without** the id: it runs the very same bundle and loses only the history filing. Do not go looking for the bundle; the bundle was never in question. diff --git a/pipelex-vibe/skills/pipelex-run/references/published-address.md b/pipelex-vibe/skills/pipelex-run/references/published-address.md index 61555c65..68ebef69 100644 --- a/pipelex-vibe/skills/pipelex-run/references/published-address.md +++ b/pipelex-vibe/skills/pipelex-run/references/published-address.md @@ -4,7 +4,7 @@ Read this at step 1 when the target is a published method's address, passed as ` ## It pairs with nothing -An address is a complete run source, so **an address pairs with nothing**: a `method_dir`, `files` or a `method_id` beside it is refused with an `input_domain` error before anything runs. Every call carries the `method_ref` alone. +An address is a complete run source, so **an address pairs with nothing**: a `method_dir`, `files` or a `method_id` beside it is refused as `client.argument_invalid` before anything runs. Every call carries the `method_ref` alone. ## It floats without a tag diff --git a/pipelex-vibe/skills/pipelex-synthetic-inputs/references/photograph.md b/pipelex-vibe/skills/pipelex-synthetic-inputs/references/photograph.md index 0d8d64e2..09ff5219 100644 --- a/pipelex-vibe/skills/pipelex-synthetic-inputs/references/photograph.md +++ b/pipelex-vibe/skills/pipelex-synthetic-inputs/references/photograph.md @@ -58,7 +58,7 @@ Its description says what changes (the side, the angle, the damage) and repeats **A room seen from two places keeps its materials and loses its walls.** The model draws what the description puts on the left and the right of the frame, but as a view straight down the room, wherever the photographer was said to stand. A second view "from the opposite corner", with the windows on its left and the fireplace on its right, therefore puts the two on facing walls, when the first photograph had them side by side. Write the room's plan before the first description, naming what is on each wall, and describe the second view by the wall it faces and what stands on the walls to its left and right: "facing the fireplace wall, the two windows on the right-hand wall, a bare wall on the left". -Follow each run with `mthds_run_status` at the hint it gives, then `mthds_run_results` once it is terminal. A failed run is reported with its `failure_message` verbatim, and that photograph is left without a path; do not retry it with a reworded description on a guess. +Follow each run with `mthds_run_status` at the hint it gives, then `mthds_run_results` once it is terminal. A failed run is reported with its problem, `run_error` (`error` on the status), verbatim, and that photograph is left without a path; do not retry it with a reworded description on a guess. ## 3. Save it diff --git a/pipelex-vibe/skills/shared/credentials.md b/pipelex-vibe/skills/shared/credentials.md index ace28882..314b0956 100644 --- a/pipelex-vibe/skills/shared/credentials.md +++ b/pipelex-vibe/skills/shared/credentials.md @@ -1,6 +1,6 @@ # Connecting the Pipelex workshop, and its key -Read this when an MCP-backed skill sends you here: because one of the plugin's `mthds_*` tools is absent from the session, or because a call returned a `config`-class error about the API key. It says what to tell the user on Mistral Vibe, and nothing more: whether the skill stops there or carries on without the tool is the skill's own rule, which this file changes in neither direction. +Read this when an MCP-backed skill sends you here: because one of the plugin's `mthds_*` tools is absent from the session, or because a call returned a problem about the API key, `auth.missing_credential`, `auth.invalid_credential` or `auth.credential_expired`. It says what to tell the user on Mistral Vibe, and nothing more: whether the skill stops there or carries on without the tool is the skill's own rule, which this file changes in neither direction. ## The tool is absent @@ -12,6 +12,8 @@ The Pipelex connector's `pipelex_*` tools, when the session has them, belong to The server authenticates to the API with **`PIPELEX_API_KEY`**. It uses the key its host hands it, which on Mistral Vibe is only one written into the `env` table of its `[[mcp_servers]]` entry, since Mistral Vibe passes a stdio MCP server only a few basic variables of your shell, such as `HOME` and `PATH`, and none of your `PIPELEX_` ones. When the host hands it none, it reads the key saved in `~/.pipelex/.env`, or in the `.env` of `PIPELEX_HOME` when that variable reaches it, which on Mistral Vibe also takes the entry's `env` table, afresh on every call, so a key saved while the session runs is used from the next call with no restart. -So a `config`-class error about the key is answered by the workshop's login, which the user runs themselves in a terminal: **`npx -y @pipelex/mcp@latest login`** opens the browser on app.pipelex.com, mints a key for the account's current organization and saves it in that file (`--paste` reads one created in the app instead, for a machine with no browser). The pipelex CLI's `pipelex login` saves to the same file, so a key it saved counts too. When the error's hint says the host's own key was refused, the saved one is never consulted until that key is removed or replaced in the entry's `env` table. Never read that file or print a key yourself. +So a problem about the key is answered by the workshop's login, which the user runs themselves in a terminal: **`npx -y @pipelex/mcp@latest login`** opens the browser on app.pipelex.com, mints a key for the account's current organization and saves it in that file (`--paste` reads one created in the app instead, for a machine with no browser). The pipelex CLI's `pipelex login` saves to the same file, so a key it saved counts too. When the tool's summary says the host's own key was refused, the saved one is never consulted until that key is removed or replaced in the entry's `env` table. Never read that file or print a key yourself. The plugin's validation hook reads `PIPELEX_API_KEY` from Mistral Vibe's environment alone, never from that file, so with only a saved key it still lints and formats each edit but skips validating it against the API: exporting `PIPELEX_API_KEY` in the shell Mistral Vibe starts from restores that stage. + +`auth.forbidden` is not about the key: the platform refused the action for the role the key's owner holds in the organization, and its `detail` names that role and what the action needs. No login or new key changes a role, so relay it as it came and never send the user to the login for it. diff --git a/pipelex-vibe/skills/shared/writing-mthds.md b/pipelex-vibe/skills/shared/writing-mthds.md index 0908d577..308265d5 100644 --- a/pipelex-vibe/skills/shared/writing-mthds.md +++ b/pipelex-vibe/skills/shared/writing-mthds.md @@ -704,7 +704,7 @@ A dry run composes the document for real against mock inputs, which checks the t **The catalog stores no template file yet**: `mthds_save_method` takes `.mthds` and `.py` files alone, so a saved method whose step names a template file does not load by its id, while its directory still validates and runs as `method_dir`. -**A `template_check_warning` in a valid verdict's `warnings`** is the template check's finding in the file a step names, located by its `pipe_code`, `template_file` and `template_location`, such as a field that matches no input of the step. It never changes `is_valid`, but the printed file may show it. A skill that writes the method fixes it in the template it wrote, or in the step, and validates again; a template the user supplied is theirs, so name the finding and ask before changing it. A skill that only reads or runs the method reports it with the verdict. +**A `pipelex.docgen.template_warning` in a valid verdict's `warnings`** is the template check's finding in the file a step names, a problem item located at the step's pipe (`location.pipe`) whose `params` carry `template_file`, the file as the step names it, and `template_location`, where in the file, such as a field that matches no input of the step. It never changes `is_valid`, but the printed file may show it. A skill that writes the method fixes it in the template it wrote, or in the step, and validates again; a template the user supplied is theirs, so name the finding and ask before changing it. A skill that only reads or runs the method reports it with the verdict. ### PipeFunc — call a Python function of the method's folder diff --git a/pipelex/skills/pipelex-catalog/SKILL.md b/pipelex/skills/pipelex-catalog/SKILL.md index d5eeba8c..8b70819a 100644 --- a/pipelex/skills/pipelex-catalog/SKILL.md +++ b/pipelex/skills/pipelex-catalog/SKILL.md @@ -20,7 +20,7 @@ Every gesture between a bundle directory and the organization's catalog: [list a - **`mthds_list_methods`**, **`mthds_save_method`**, **`mthds_publish_method`** and **`mthds_get_method`** are required, with no fallback. - **If the catalog tools are absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Claude Code. Never report a method id, a name, a version, or a method as saved or published when the answer did not come from these tools. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. ## Guards @@ -66,10 +66,10 @@ The target is a bundle directory. | a templated bundle answers `is_valid: false`, its template *not supplied with its bundle* | expected, as step 4 says: the draft runs only from its directory and cannot be published to run by id. **Never route it to editing** | | a save or a publish answers `is_valid: false` | a **produced verdict**, not an error: the save stored the draft anyway, and the publish published nothing. Report `validation_errors[]`; route a contract-preserving fix to `/pipelex-edit`, a structural one to `/pipelex-design` | | the bundle is valid with pending signatures | A **valid bundle with pending signatures is saved**, as a draft: say plainly that the method does not run yet, and which signatures are still open | -| `input_domain` at `expected_updated_at`: the draft moved since this directory synced, or it holds a pulled version | nothing was written. Read [conflict.md](references/conflict.md) before replying: unless it finds this session's own save, give the user the timestamps and the ways forward it describes. **Never choose between them.** | -| `input_domain` at `expected_draft_updated_at` | nothing was published: the draft moved since it was seen. Publish only once the user has seen it, saved or pulled, **never under the token the refusal names** | -| `input_domain` at `method_id` | read [unknown-id.md](references/unknown-id.md) before concluding anything: several faults land there. A dead link is removed only on the user's yes, the one thing this skill ever takes off disk | -| a create fails on a timeout or a transport fault | **does not retry.** A create carries no idempotency key yet, so a retry mints a second method: list the catalog first and see whether the first one landed | +| a problem at `expected_updated_at`: the draft moved since this directory synced, or it holds a pulled version | nothing was written. Read [conflict.md](references/conflict.md) before replying: unless it finds this session's own save, give the user the timestamps and the ways forward it describes. **Never choose between them.** | +| a problem at `expected_draft_updated_at` | nothing was published: the draft moved since it was seen. Publish only once the user has seen it, saved or pulled, **never under the token the refusal names** | +| `pipelex.catalog.not_found`, or a problem at `method_id` | read [unknown-id.md](references/unknown-id.md) before concluding anything: its `code` tells the faults apart. A dead link is removed only on the user's yes, the one thing this skill ever takes off disk | +| a create answers `client.outcome_unknown` | **does not retry.** A retry mints a second method: list the catalog first and see whether the first one landed | | the pull's directory holds a bundle of its own, or a link naming another method | somebody else's work: pull into another directory | | the pull's directory is linked to this method, files identical | only the link's `synced_updated_at` was refreshed: say the directory was already up to date | | linked, files differ, the saved method has **not** moved | the difference is local work this directory never saved: offer to [save](#save) it, or to pull into a new sibling directory to compare | @@ -81,4 +81,4 @@ The target is a bundle directory. - [python.md](references/python.md): the bundle holds a `PipeFunc`, before choosing `python`. - [link-file.md](references/link-file.md): a save's `link_file` came back `written: false`. - [conflict.md](references/conflict.md): a save refused at `expected_updated_at`, or a restore. -- [unknown-id.md](references/unknown-id.md): an `input_domain` error at `method_id`. +- [unknown-id.md](references/unknown-id.md): a miss, or a problem at `method_id`. diff --git a/pipelex/skills/pipelex-catalog/references/conflict.md b/pipelex/skills/pipelex-catalog/references/conflict.md index fb2a1c31..47aed0e5 100644 --- a/pipelex/skills/pipelex-catalog/references/conflict.md +++ b/pipelex/skills/pipelex-catalog/references/conflict.md @@ -1,6 +1,6 @@ # When a save is refused at `expected_updated_at`, or a version is restored -Read this when `mthds_save_method` answers an `input_domain` error at `expected_updated_at`, or before saving a directory that holds a pulled version because the user asked to restore it, before replying to the user. A refusal writes nothing, not the draft and not the link. A conflict names the draft's current `updated_at` and the token the save was sent under; a save refused because the directory holds a pulled version names the token a restore takes. Only the draft is at stake: published versions never change, and nothing below publishes. +Read this when `mthds_save_method` answers a problem at `expected_updated_at`, or before saving a directory that holds a pulled version because the user asked to restore it, before replying to the user. A refusal writes nothing, not the draft and not the link. A conflict is `pipelex.catalog.update_conflict`, whose `message` names the draft's current `updated_at` and the token the save was sent under; a save refused because the directory holds a pulled version is `client.argument_invalid` with `params.reason` `version_pulled`, whose `message` names the token a restore takes. Only the draft is at stake: published versions never change, and nothing below publishes. **First, does the directory hold a pulled version?** When `pipelex-method.json` records a `synced_version`, or the refusal says the directory holds one, the files here are version n, pulled to read or to start over from, perhaps edited since, and saving them replaces the draft with them: a restore. Unless the user asked for it, say so and give the two ways forward: pull the draft back into this directory to go on working on the draft, or restore, which makes these files, edits included, the draft. The pull writes over the version's untouched files freely, since the catalog stores them, and refuses a file edited since the version pull: those edits survive only a restore or a copy the user moves aside first, so never answer that refusal with `overwrite: true` without saying the edits are lost. A restore, made only on the user's request or an explicit yes, is the same call with `expected_updated_at` set to the `updated_at` the version pull reported, which the link records as `synced_updated_at` and the refusal names too, and `python` as the version's `.py` files, or `[]` when it has none, since an omitted `python` keeps the draft's. That token is the draft as the pull found it, so a draft saved since then refuses the restore: that refusal is a conflict, answered as the last paragraph and its two ways forward say, and saving over it is this restore sent with the draft's current `updated_at`, on the user's yes once they have seen both timestamps. Never take the draft's current `updated_at` for a restore before that refusal, from a pull or from anywhere else: it would restore over a draft nobody here has seen. A restore publishes nothing; a publish of the restored draft is a request of its own. diff --git a/pipelex/skills/pipelex-catalog/references/unknown-id.md b/pipelex/skills/pipelex-catalog/references/unknown-id.md index 2dd255c2..80112b26 100644 --- a/pipelex/skills/pipelex-catalog/references/unknown-id.md +++ b/pipelex/skills/pipelex-catalog/references/unknown-id.md @@ -1,15 +1,19 @@ -# An error at `method_id` +# A miss, or a problem at `method_id` -Read this when `mthds_save_method`, `mthds_publish_method` or a pull's `mthds_get_method` answers an `input_domain` error at `method_id`, before concluding anything about the directory's link. The skill's guard on the link holds throughout: it is removed only on the user's yes. +Read this when `mthds_save_method`, `mthds_publish_method` or a pull's `mthds_get_method` answers `pipelex.catalog.not_found`, or another problem located at `method_id`, before concluding anything about the directory's link. The skill's guard on the link holds throughout: it is removed only on the user's yes. -An unknown `method_id` comes back at that location, and so do several other faults: a payload the platform rejected, an organization-context failure, and the workshop's own refusal when this directory's link names a *different* method from the id being saved. **The location alone never tells them apart**, so read the message and the hint before doing anything: only the not-found answer names `pipelex-method.json` and the `api_host` and explains that the catalog is org-scoped, so a method from another organization reads exactly like a miss. Anything else is a different fault: the link is not dead, it stays where it is, and the fix is to the call. +Several faults land on the same id, and **the problem's `code` tells them apart**, never its location or its wording. Only `pipelex.catalog.not_found` whose `params.resource` is `method` is a miss: the catalog is org-scoped, so a method from another organization reads exactly like one. Anything else is a different fault, the link is not dead, it stays where it is, and the fix is to the call: -**A version suffix is refused there too, and is not a miss.** A save and a publish take the bare id, since both act on the draft, so `mt_…@` is refused before anything is sent: call again with the bare id, and to publish an old version's content again, pull that version, restore it as the draft and publish that. A pull of a version the method never had names the versions it has: offer one of those, or the draft. +- `client.target_exists` at `method_id` is the workshop's own refusal when this directory's link names a *different* method from the id being saved. Its `message` names both and what to pass instead. +- `client.argument_invalid` at `method_id` is a call the workshop refused before sending it, its `params.reason` saying why. **A version suffix is refused there, as `version_suffix`, and is not a miss.** A save and a publish take the bare id, since both act on the draft, so `mt_…@` is refused before anything is sent: call again with the bare id, and to publish an old version's content again, pull that version, restore it as the draft and publish that. +- `pipelex.catalog.not_found` whose `params.resource` is `version` is a pull of a version the method never had. Its `message` names the versions it has: offer one of those, or the draft. +- `method.package_invalid` with `params.reason` `empty_tree` is a pull of a method whose stored source holds no file yet. It is not a miss: relay it as the pull's report step says. +- Any other code, such as a payload the platform rejected or a failure of the organization's context, is relayed with its `detail` and `next_step`. -**A save's miss is checked against a read first.** When a save answers that the id is not visible, call `mthds_get_method` on the same bare id without `output_dir`: when it reads the method, the id is alive and this platform has no draft save yet, a platform older than drafts. Say so and stop; the link stays and nothing here creates a method. +**A save's miss is checked against a read first.** When a save answers `pipelex.catalog.not_found`, call `mthds_get_method` on the same bare id without `output_dir`: when it reads the method, the id is alive and this platform has no draft save yet, a platform older than drafts. Say so and stop; the link stays and nothing here creates a method. -When the hint does say the id is not visible, and a read does not find it either, report it **with the `api_host` the link file records** — that is what makes it diagnosable: the link was made against another plane, or with another organization's key. +When a read does not find it either, report the miss **with the `api_host` the link file records** — that is what makes it diagnosable: the link was made against another plane, or with another organization's key. Then offer to save the directory as a **new** method. That needs the stale link gone first: the workshop refuses a create into a directory another link claims, rather than minting a duplicate nobody can delete. So ask, and on a yes remove `pipelex-method.json` and run the create, which writes a fresh link. -**A pull or a publish has no link to judge.** When the error came from `mthds_get_method` or `mthds_publish_method`, nothing was written or published and nothing on disk is touched. An empty stored source answers at the same location and is not a miss: relay it as the pull's report step says. Otherwise relay the answer and its hint, and when the hint says the id is not visible, say that a method saved from another organization, or on another plane, reads exactly like a miss, and offer to find the method by name, as the skill's "List and find" says. +**A pull or a publish has no link to judge.** When the problem came from `mthds_get_method` or `mthds_publish_method`, nothing was written or published and nothing on disk is touched. Relay its `detail` and `next_step`, and on a miss say that a method saved from another organization, or on another plane, reads exactly like one, and offer to find the method by name, as the skill's "List and find" says. diff --git a/pipelex/skills/pipelex-design/SKILL.md b/pipelex/skills/pipelex-design/SKILL.md index 2655f9f8..7e2952be 100644 --- a/pipelex/skills/pipelex-design/SKILL.md +++ b/pipelex/skills/pipelex-design/SKILL.md @@ -22,7 +22,7 @@ Design a `.mthds` method **contract-first**, directly or stepwise (step 3). A st - **`mthds_validate`** and **`mthds_inputs_template`** are required: this skill never guesses at validity. - **If the tools are absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Claude Code. Do not write `.mthds` files without validation available. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never silently skip validation. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never silently skip validation. ## Guards @@ -63,7 +63,7 @@ Design the whole graph in memory, then write `main.mthds` in the bundle home, to Call `mthds_validate`. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. -Branch on the **structured verdict**, never on transport: `is_valid: true` is complete with `is_runnable: true` and nothing pending, and otherwise a scaffold whose backlog is the summary's `## Pending signatures`; on `is_valid: false`, fix from `validation_errors[]` and the summary's locators, then re-validate. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `template_check_warning`. +Branch on the **structured verdict**, never on transport: `is_valid: true` is complete with `is_runnable: true` and nothing pending, and otherwise a scaffold whose backlog is the summary's `## Pending signatures`; on `is_valid: false`, fix from `errors[]`, then re-validate. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `pipelex.docgen.template_warning`. ### 6. The runnable gate and delivery @@ -76,7 +76,7 @@ For a completed method, validate once more and confirm **`is_valid: true`, `is_r 5. **Hand off**: `/pipelex-inputs` prepares the user's files, or test files with planted facts, then `/pipelex-run` runs the method, and `/pipelex-lab` writes answer keys and scores the runs; `/pipelex-catalog` saves it under an `mt_…` id; `/pipelex-integrate` wires it into a codebase (a `package.json` or a `pyproject.toml`), and with neither, `/pipelex-scaffold` creates an app around it. 6. Search the whole project for `sources.json` files carrying `"generator": "pipelex-integrate"` — `grep -rl '"pipelex-integrate"' --include=sources.json .` — which sit beside each generated tree, never beside the bundle. Keep each one whose `sources` name a `.mthds` file this change rewrote, moved or removed, or whose `templates` name a template file it changed, **or whose `bundle_dir` holds a `.mthds` file this change created** — a new file is in no `sources` map, yet the call site loads every `.mthds` file under that directory. For each, say the generated types in that directory are now stale and offer `/pipelex-integrate` to refresh them: it regenerates in place and touches the call site only if the types no longer fit it. -**Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a `config`-class error included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. +**Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a problem in the `account` domain included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. ## Re-entry @@ -88,8 +88,8 @@ For a completed method, validate once more and confirm **`is_valid: true`, `is_r | Condition | Do this | |---|---| -| `status: "error"`, class `input_domain` | fix the call | -| `status: "error"`, class `runtime` | report it, and retry once before stopping | +| `status: "error"`, `domain: "input"` | fix the call | +| any other `status: "error"` | report it, after one retry when its `retry` is `"yes"` | | validation fails twice on the same construct, or the client contract itself looks wrong | pause and show the user | ## References diff --git a/pipelex/skills/pipelex-design/references/stepwise.md b/pipelex/skills/pipelex-design/references/stepwise.md index 9604046c..b604c77a 100644 --- a/pipelex/skills/pipelex-design/references/stepwise.md +++ b/pipelex/skills/pipelex-design/references/stepwise.md @@ -48,7 +48,7 @@ Given pending signature `S` with frozen `inputs`, `output`, `description`, and ` The new file bounds the ordinary fix: - **Contract mismatch:** conform the definition to the frozen header. If the header itself is wrong, that is a propagating contract change; pause and revise the parent region deliberately rather than silently changing the header. -- **Other semantic errors:** use `validation_errors[]`, the Markdown locators, and the relevant section of the authoring reference; fix the added file and re-validate. +- **Other semantic errors:** use the verdict's `errors[]`, each item's `code`, `detail` and `location`, and the relevant section of the authoring reference; fix the added file and re-validate. ## Stopping early diff --git a/pipelex/skills/pipelex-edit/SKILL.md b/pipelex/skills/pipelex-edit/SKILL.md index 56d16c96..97fa6ea9 100644 --- a/pipelex/skills/pipelex-edit/SKILL.md +++ b/pipelex/skills/pipelex-edit/SKILL.md @@ -25,7 +25,7 @@ Modify an existing MTHDS method bundle. There are two classes of change; this sk - **`mthds_validate`** is required: it proves every edit. **Never declare an edit done on the hook's silence alone**: its semantic stage is skipped without an API key. - **If the tool is absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Claude Code. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. - **`mthds_inputs_template`** is needed only by Step 6, when the edit could have touched the input template. **`mthds_models`** serves a model change in Step 4, and its absence is no stop: the model references say what to do without it. ## Mode Selection @@ -57,7 +57,7 @@ Check the requested change against the scope split at the top. Structural or con Validate the whole bundle **before editing**: call `mthds_validate` on the bundle directory, and branch on the structured verdict, never on transport. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. - `is_valid: true` → record whether it is runnable or a scaffold (non-empty `pending_signatures`). That same state must hold after your edits. -- `is_valid: false` → the bundle is broken **before** your change: surface the `validation_errors[]` and the Markdown summary, and offer to repair first. **Never edit on a broken baseline.** +- `is_valid: false` → the bundle is broken **before** your change: surface the `errors[]` and the Markdown summary, and offer to repair first. **Never edit on a broken baseline.** ### Step 4: Apply the edits @@ -71,7 +71,7 @@ Before editing a construct you have not touched recently, read [the MTHDS refere ### Step 5: Re-validate -Same whole-bundle `mthds_validate` call as Step 3. The bar is the **baseline verdict restored**: `is_valid: true`, and the runnable or scaffold state unchanged (a renamed pending signature renames its backlog entry; nothing else in the pending set moves). **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `template_check_warning`. On `is_valid: false` the failure is in your edit: use the summary's locators, fix, re-validate. On `status: "error"` the edit is applied but **unproven** — never report it as done: tell the user it is on disk but could not be validated, and offer to restore the pre-edit content you still hold from Step 1, or to retry once the server is reachable again. +Same whole-bundle `mthds_validate` call as Step 3. The bar is the **baseline verdict restored**: `is_valid: true`, and the runnable or scaffold state unchanged (a renamed pending signature renames its backlog entry; nothing else in the pending set moves). **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `pipelex.docgen.template_warning`. On `is_valid: false` the failure is in your edit: use the summary's locators, fix, re-validate. On `status: "error"` the edit is applied but **unproven** — never report it as done: tell the user it is on disk but could not be validated, and offer to restore the pre-edit content you still hold from Step 1, or to retry once the server is reachable again. ### Step 6: Inputs refresh check @@ -83,14 +83,14 @@ State what changed (files and constructs), give the verdict line from the summar **Generated types may now be stale.** Search the whole project for `sources.json` files carrying `"generator": "pipelex-integrate"` — `grep -rl '"pipelex-integrate"' --include=sources.json .` — which sit beside each generated tree, never beside the bundle. Keep each one whose `sources` name a `.mthds` file this change rewrote, moved or removed, or whose `templates` name a template file it changed, **or whose `bundle_dir` holds a `.mthds` file this change created** — a new file is in no `sources` map, yet the call site loads every `.mthds` file under that directory. For each, say the generated types in that directory are now stale and offer `/pipelex-integrate` to refresh them: it regenerates in place and touches the call site only if the types no longer fit it. -**Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a `config`-class error included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. +**Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a problem in the `account` domain included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. ## Stops | Condition | Do this | |---|---| -| `status: "error"`, class `input_domain` | fix the call | -| `status: "error"`, class `runtime` | report it, and retry once before stopping | +| `status: "error"`, `domain: "input"` | fix the call | +| any other `status: "error"` | report it, after one retry when its `retry` is `"yes"` | | the same construct fails twice after your edit | pause and show the user instead of thrashing | ## References diff --git a/pipelex/skills/pipelex-explain/SKILL.md b/pipelex/skills/pipelex-explain/SKILL.md index 4ed10471..06b775c8 100644 --- a/pipelex/skills/pipelex-explain/SKILL.md +++ b/pipelex/skills/pipelex-explain/SKILL.md @@ -23,7 +23,7 @@ Read a method and say what it does, in plain language. Reading costs nothing and - **A bundle directory needs no tool at all**: it is explained from its source, and `mthds_validate`, when present, adds the verdict line. Never refuse to explain a local bundle because the workshop is not connected. - **A catalog id or a published address needs the workshop**, since nothing of it is on disk. Where `mthds_get_method` is absent while the other tools answer, an id is explained at contract level, as an address is, and the explanation says which reading it is: a narrower explanation, not a stop. - **If the workshop is absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Claude Code. That stop is only for a target that lives on the platform — a bundle directory on disk is still explained from its source, with the verdict line left out. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Same scope: on a local bundle a `config` error costs the verdict line and nothing else — carry on and say it was not checked. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Same scope: on a local bundle such a problem costs the verdict line and nothing else — carry on and say it was not checked. ## Guards @@ -43,7 +43,7 @@ A `PipeSignature` is **pending only when no concrete pipe of the same code exist ### 3. The verdict, when the workshop is there -One `mthds_validate` call on the bundle directory. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. **From a folder, explain the `.mthds` files in `files_sent`, naming any you read that it leaves out.** **A single file goes as `files` instead**, its `{path}` and then those of the templates its steps name: its folder may hold other methods. The call adds two things to the explanation: the **verdict line** (whether it is valid, whether it is runnable, what is still pending) and, when the verdict carries a `main_pipe`, the **main pipe's typed signature**: its namespaced ref, each declared input with its concept and whether it is required, and the concept it produces. Into the method's directory the workshop also writes its flowchart as `method-graph.html`, rewritten on every validation, and reports it as `graph_page`. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `template_check_warning`. +One `mthds_validate` call on the bundle directory. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. **From a folder, explain the `.mthds` files in `files_sent`, naming any you read that it leaves out.** **A single file goes as `files` instead**, its `{path}` and then those of the templates its steps name: its folder may hold other methods. The call adds two things to the explanation: the **verdict line** (whether it is valid, whether it is runnable, what is still pending) and, when the verdict carries a `main_pipe`, the **main pipe's typed signature**: its namespaced ref, each declared input with its concept and whether it is required, and the concept it produces. Into the method's directory the workshop also writes its flowchart as `method-graph.html`, rewritten on every validation, and reports it as `graph_page`. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `pipelex.docgen.template_warning`. Without the tool, explain from the source and **say the verdict was not checked**. Your own reading of the source is not a guess: the pipe types, the concepts and step 2's backlog are yours to state, saying whose reading it is. But do not present a validation verdict, a typed signature or a pending list as the workshop's when the workshop did not answer, and do not guess at validity. **On a target that is not on disk there is no such fallback.** @@ -86,11 +86,11 @@ Output: final_output | the workshop is absent, on an id or an address | stop per the Requirements: there is nothing to read | | `mthds_get_method` is absent while the other tools answer | explain the id at contract level, say the source was not read, and name the cause [not-on-disk.md](references/not-on-disk.md) gives | | an id's source comes back `truncated` | name the files you could not read and say the explanation is partial. Never describe a withheld file's pipes as absent. | -| an id is refused at `method_id` | give the tool's answer: an unknown id and an empty stored source are different answers, and an empty one is somebody's draft, not a wrong id | -| a selector call answers a no-verdict error | report the error and its `hint` verbatim; hosted address and id resolution is not live everywhere yet | +| an id is refused | give the tool's answer: an unknown id (`pipelex.catalog.not_found`) and an empty stored source (`method.package_invalid`) are different answers, and an empty one is somebody's draft, not a wrong id | +| a selector call answers a no-verdict problem | report its `detail` and `next_step` verbatim; hosted address and id resolution is not live everywhere yet | | a **local bundle** does not validate | explain it anyway from the source, say what the verdict was, and route a fix to `/pipelex-edit` or `/pipelex-design` | -| a **catalog id** does not validate | explain it from the source read above with `validation_errors[]` beside it, and say the fix is not on this disk | -| a published **address** does not validate | report `validation_errors[]` and stop: there is no source to explain, and the fix is upstream | +| a **catalog id** does not validate | explain it from the source read above with its `errors[]` beside it, and say the fix is not on this disk | +| a published **address** does not validate | report its `errors[]` and stop: there is no source to explain, and the fix is upstream | | the verdict carries no `main_pipe` | say so, and which cause the tool's message points to: the method settles no entry pipe, the contract did not come back whole, or the workshop predates the field. Do not reconstruct a signature from the input template. | | the user wants the method changed, or a saved method's files on disk | route: `/pipelex-edit` for a contract-preserving fix, `/pipelex-design` for a structural one, `/pipelex-catalog` to bring a saved method to disk | diff --git a/pipelex/skills/pipelex-explain/references/not-on-disk.md b/pipelex/skills/pipelex-explain/references/not-on-disk.md index d2c8a31a..39b19058 100644 --- a/pipelex/skills/pipelex-explain/references/not-on-disk.md +++ b/pipelex/skills/pipelex-explain/references/not-on-disk.md @@ -6,7 +6,7 @@ The two targets part company on ownership rather than convenience. **A catalog i ## A catalog id: read it in full -Call `mthds_get_method` with the `method_id`, as the skill's step 1 says. The `files` it returns are explained **exactly as a bundle on disk is**, through the skill's steps 1 to 5, with the returned contents standing in for the files you would have read. The verdict of step 3 is one `mthds_validate` call naming the content that was read: `mt_…@draft` when the result's `version` is `draft`, and `mt_…@` for version n. A platform that does not resolve versions yet refuses the suffix, with a hint saying that a bare id reads the draft there: validate the bare id then, which reads the same stored content on that platform, and say so. +Call `mthds_get_method` with the `method_id`, as the skill's step 1 says. The `files` it returns are explained **exactly as a bundle on disk is**, through the skill's steps 1 to 5, with the returned contents standing in for the files you would have read. The verdict of step 3 is one `mthds_validate` call naming the content that was read: `mt_…@draft` when the result's `version` is `draft`, and `mt_…@` for version n. A platform that does not resolve versions yet refuses the suffix, the problem's `message` saying that a bare id reads the draft there: validate the bare id then, which reads the same stored content on that platform, and say so. **A bare id reads the draft here and the latest published version everywhere else.** `mthds_get_method` reads a bare id's draft, which is what the next save replaces, while a validation, an inputs template or a run of the same bare id reads the latest published version, what the method's callers run. So never validate a draft's source under the bare id, and say which content the explanation is of. The result's `publish_state` says how the two stand: `draft_ahead` means callers of the bare id run version `latest_version`, which differs from what you explained, so say so and offer to explain `mt_…@`; `draft_unchanged` means they run what you explained; `never_published` means a bare id runs nothing yet. @@ -18,7 +18,7 @@ Three things about the returned set are worth knowing before you describe it: ## Without `mthds_get_method` -When the other tools answer and `mthds_get_method` does not, read the id at contract level exactly as an address is read below, with `method_id` as the selector, and say that the source was not read rather than implying there was none to read. A bare id there is the latest published version, and one never published is refused as `method_not_published`, whose draft `mt_…@draft` can be read instead; say which you read. **The cause is a local workshop that predates the tool**, which `npx -y @pipelex/mcp@latest` refreshes; say so. The Pipelex connector's `pipelex_*` tools, when the session has them too, belong to a different server with no tool of this name, so they neither cause this nor stand in for the workshop. +When the other tools answer and `mthds_get_method` does not, read the id at contract level exactly as an address is read below, with `method_id` as the selector, and say that the source was not read rather than implying there was none to read. A bare id there is the latest published version, and one never published is refused as `pipelex.catalog.not_published`, whose draft `mt_…@draft` can be read instead; say which you read. **The cause is a local workshop that predates the tool**, which `npx -y @pipelex/mcp@latest` refreshes; say so. The Pipelex connector's `pipelex_*` tools, when the session has them too, belong to a different server with no tool of this name, so they neither cause this nor stand in for the workshop. ## A published address: its contract @@ -31,5 +31,5 @@ When the other tools answer and `mthds_get_method` does not, read the id at cont A published address has no source to fall back on, and neither has an id read at contract level, so these verdicts are said rather than filled in. An id read in full still has its source. - **The verdict is positive but carries no `main_pipe`.** The method settles no entry pipe, the contract did not come back whole, or the workshop predates the field — the same three causes `/pipelex-integrate` names, and the one-line signature in the text summary is missing in all three. Say the verdict was positive and that it carries no signature to describe the contract with, and name which of the three the tool's own message points to. -- **The verdict is `is_valid: false`.** There is no `main_pipe` on an invalid verdict and `mthds_inputs_template` answers with `validation_errors[]` rather than shapes, so nothing about the method is readable **from the verdict** — though for an id read in full the source still is, and an invalid stored method is worth explaining from its source with the errors beside it. Report the errors as they came back. **Do not route a remote target to `/pipelex-edit` or `/pipelex-design`**: a stored method is fixed where it is edited — `/pipelex-catalog` is what brings it to disk first — and a published address is fixed in the repository it names. -- **The id is refused rather than read.** An unknown id and a method whose stored source is empty both arrive as `input_domain` at `method_id`: the first says no such method is visible to the API key's organization, which a method from another organization reads exactly like; the second says the row exists and holds no source yet. Give the one the tool gave, as the skill's stop table says. +- **The verdict is `is_valid: false`.** There is no `main_pipe` on an invalid verdict and `mthds_inputs_template` answers with `errors[]` rather than shapes, so nothing about the method is readable **from the verdict** — though for an id read in full the source still is, and an invalid stored method is worth explaining from its source with the errors beside it. Report the errors as they came back. **Do not route a remote target to `/pipelex-edit` or `/pipelex-design`**: a stored method is fixed where it is edited — `/pipelex-catalog` is what brings it to disk first — and a published address is fixed in the repository it names. +- **The id is refused rather than read.** An unknown id and a method whose stored source is empty are told apart by the problem's `code`: the first is `pipelex.catalog.not_found`, no such method visible to the API key's organization, which a method from another organization reads exactly like; the second is `method.package_invalid` at `method_id`, the row existing and holding no source yet. Give the one the tool gave, as the skill's stop table says. diff --git a/pipelex/skills/pipelex-inputs/SKILL.md b/pipelex/skills/pipelex-inputs/SKILL.md index 575fbd31..f304bb49 100644 --- a/pipelex/skills/pipelex-inputs/SKILL.md +++ b/pipelex/skills/pipelex-inputs/SKILL.md @@ -22,8 +22,8 @@ The one entry point for a method's inputs, through to run-ready inputs. - **`mthds_inputs_template`** is required: never hand-derive the template from the `.mthds` source. - **If the tool is absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Claude Code. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never silently improvise a template. -- **`mthds_prepare_inputs`** is required at step 5, under the same two stops; never hand-fake a storage reference. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never silently improvise a template. +- **`mthds_prepare_inputs`** is required at step 5, under the same two stops, except `auth.forbidden` on a call with `kind` (see Stops); never hand-fake a storage reference. - **`mthds_list_methods`** and **`mthds_list_files`** are optional: without the first, ask for a saved method's `mt_…` id. ## Mode @@ -45,8 +45,8 @@ The one entry point for a method's inputs, through to run-ready inputs. The target takes three forms, one selector per call. - **A local bundle**, the usual case: `` is its directory, usually the one holding `main.mthds`, unless the caller names another. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. -- **A registered method**, an `mt_…` id with no local bundle in play, as `method_id`: bare, the latest published version; `@draft`, the draft; `@`, version n. **Say which one the template came from** (`method_version`) and offer the run on that same form; a bare id never published is refused as `method_not_published`, and `mt_…@draft` is then the target. `` is a directory the user names, by default a new `.//` without the suffix. -- **A published method**, as `method_ref: "github.com//[/][@]"`: read [references/published-address.md](references/published-address.md) before the first call. **An address with no tag is accepted, and it floats**: say so in one line, recommend the tag, and carry on. +- **A registered method**, an `mt_…` id with no local bundle in play, as `method_id`: bare, the latest published version; `@draft`, the draft; `@`, version n. **Say which one the template came from** (`method_version`) and offer the run on that same form; a bare id never published is refused as `pipelex.catalog.not_published`, and `mt_…@draft` is then the target. `` is a directory the user names, by default a new `.//` without the suffix. +- **A published method**, as `method_ref: "github.com//[/][@]"`: read [published-address.md](references/published-address.md) before the first call. **An address with no tag is accepted, and it floats**: say so in one line, recommend the tag, and carry on. ### 2. The template @@ -64,8 +64,8 @@ Evaluated in order: | No clear signal (e.g. right after `/pipelex-design`, with no further context) | **Template**, then offer to populate | - **Template**: replace each file-ish mock URL (an `https://` URL on a `.invalid` host) with `""`, never `""`; save, show it with its path, and offer synthetic data or the user's files. -- **Synthetic**: read [references/synthetic.md](references/synthetic.md) before generating anything. **`pipelex-synthetic-inputs` is the file factory**, and makes every file input. Invoke it with `/pipelex-synthetic-inputs`. -- **User data**: read [references/user-data.md](references/user-data.md) before matching any file to an input. +- **Synthetic**: read [synthetic.md](references/synthetic.md) before generating anything. **`pipelex-synthetic-inputs` is the file factory**, and makes every file input. Invoke it with `/pipelex-synthetic-inputs`. +- **User data**: read [user-data.md](references/user-data.md) before matching any file to an input. - **Mixed**: the user's files first, then synthetic values for what they leave unfilled; read both references. - **The team's files**: read [team-files.md](../shared/team-files.md) before asking for a file, or for one named but not on disk. @@ -75,7 +75,7 @@ Fill the step 2 template in place, a composite native's fields included ([native ### 5. Prepare the inputs for a run -`mthds_prepare_inputs` uploads each local path, `data:` URL or inline bytes at a file input to Pipelex storage. Skip the call for the Template strategy. Otherwise, for a case's copies, **first delete any `inputs.prepared.json` an earlier prepare left in ``**, which a run would read after a prepare that writes none. Skip the call too **when every file-ish value is already an `http(s)` URL or a `pipelex-storage://` reference**: a run then reads `inputs.json`. +`mthds_prepare_inputs` uploads each local path, `data:` URL or inline bytes at a file input to Pipelex storage. Skip the call for the Template strategy. Otherwise, for a case's copies, **first delete any `inputs.prepared.json` an earlier prepare left in ``**. Skip the call too **when every file-ish value is already an `http(s)` URL or a `pipelex-storage://` reference**: a run then reads `inputs.json`. **Say what is about to leave the machine, before it does**: each file and where it goes (Pipelex storage, the user's organization, through their API key), or for a folder batch too long to list, the count and the folder; in interactive mode wait for a yes, in automatic mode state it and proceed. If the user declines, stop before the call and report that the inputs stay local and are not runnable. @@ -95,24 +95,25 @@ Say what is ready, or which placeholders are left. When a codebase here does not - no calling skill asked to stop at run-ready (a user who said not to run still gets the offer: an offer is not a run); - no placeholder remains; -- **every input the template asked for is filled** — one the factory could not make is absent, passes every other check and guarantees a failed run: say which input waits on the user, and why; +- **every input the template asked for is filled** — one the factory could not make is absent: say which input waits on the user, and why; - the inputs are run-ready: prepare succeeded, or step 5 skipped it because nothing needed uploading. -The offer names the file the run reads — `inputs.prepared.json` where prepare wrote one, else `inputs.json` — and the target: the bundle, the id or the address. +The offer names the file the run reads — `inputs.prepared.json` where prepare wrote one, else `inputs.json` — and the target. ## Stops | Condition | Do this | |---|---| -| template: `is_valid: false` | report `validation_errors[]` and the summary. A local bundle is repaired first (`/pipelex-design` resumes it), then retried; a registered method through `/pipelex-edit`, not here; a published one is reported as [its reference](references/published-address.md) says | -| template: `input_domain` | an unknown `pipe_ref` or unresolvable `main_pipe`: pass an explicit `pipe_ref`. At `method_dir`, `method_id` or `method_ref`, report it in the tool's words; another organization's id reads as a miss | -| `runtime`, either call | report, and retry once | +| template: `is_valid: false` | report `errors[]` and the summary. A local bundle is repaired first (`/pipelex-design` resumes it), then retried; a registered method through `/pipelex-edit`, not here; a published one is reported as [its reference](references/published-address.md) says | +| template: `request.pipe_not_found` or `request.pipe_ambiguous` | pass an explicit `pipe_ref`. Another `domain: "input"` problem: report it in the tool's words; another organization's id reads as a miss | +| `retry: "yes"`, either call | report, and retry once | | the factory returns no path | leave that one input unfilled, carry on with the others; report the reason and ask for the user's own file. Never fabricate a value or abandon `inputs.json` | -| prepare: `input_domain` at `inputs`, `pipe_ref`, `method_id` or `method_ref` | read [references/prepare-errors.md](references/prepare-errors.md) before replying or retrying; a storage size limit at `inputs` is terminal for this attempt | -| prepare, by address: `input_domain` at `files`, or `config` (the credential first, as the requirements say) | read [references/published-address.md](references/published-address.md) before naming a cause | +| prepare with `kind`: `auth.forbidden`, or a refusal naming `kind`, or `method_id` for `method_not_found`, `method_being_deleted` or `version_suffix` | read [synthetic.md](references/synthetic.md#test-files) before preparing again without `kind` | +| prepare: an `input` or `method` problem, not a refusal of `kind` | read [prepare-errors.md](references/prepare-errors.md) before replying or retrying; a storage size limit at `inputs` is terminal for this attempt | +| prepare, by address: refused at `files`, or an `account` problem | read [published-address.md](references/published-address.md) before naming a cause | ## References -- [synthetic.md](references/synthetic.md), [user-data.md](references/user-data.md): step 3, by strategy; both for Mixed. +- [synthetic.md](references/synthetic.md), [user-data.md](references/user-data.md): step 3, by strategy. - [published-address.md](references/published-address.md): a `method_ref` target. -- [prepare-errors.md](references/prepare-errors.md): prepare's `input_domain` errors. +- [prepare-errors.md](references/prepare-errors.md): prepare's input and method problems. diff --git a/pipelex/skills/pipelex-inputs/references/prepare-errors.md b/pipelex/skills/pipelex-inputs/references/prepare-errors.md index 11396395..d6f6919d 100644 --- a/pipelex/skills/pipelex-inputs/references/prepare-errors.md +++ b/pipelex/skills/pipelex-inputs/references/prepare-errors.md @@ -1,25 +1,27 @@ # When preparation fails -Read this when `mthds_prepare_inputs` answers `status: "error"` with class `input_domain` located at `inputs`, `pipe_ref`, `method_id` or `method_ref`, before replying to the user or retrying. Unlike `mthds_inputs_template`, the tool has no produced-invalid arm: it never returns a `validation_errors[]` list. **Read the error's `location` first**, because the causes need opposite repairs. The skill's file-fidelity guard holds throughout: nothing here is a reason to transform, derive or substitute a file, or to retry with one. +Read this when `mthds_prepare_inputs` answers `status: "error"` with a problem the inputs or the method's resolution must fix (its `domain` is `input` or `method`), before replying to the user or retrying. Unlike `mthds_inputs_template`, the tool has no produced-invalid arm: it never returns a verdict with `errors[]` of its own. **Read the problem's `code` first**, because the causes need opposite repairs; the location and the wording never tell them apart. A refusal of `kind` is not this file's: on a call that passed `kind: "test"`, `client.argument_invalid` whose `params.argument` is `kind`, or is `method_id` with `params.reason` `method_not_found`, `method_being_deleted` or `version_suffix`, and `auth.forbidden` are about recording test files, which the skill answers where it passes `kind`. The skill's file-fidelity guard holds throughout: nothing here is a reason to transform, derive or substitute a file, or to retry with one. -## `location: "inputs"` and the response reports a storage size limit +## `upload_too_large`: a file over the storage size limit -This is a terminal branch for the current preparation attempt. +The workshop refuses a file over the upload ceiling before anything is sent, as `client.argument_invalid` at `inputs` whose `params.reason` is `upload_too_large`. This is a terminal branch for the current preparation attempt. -1. Report the affected input and file; quote the tool's exact `message` and `hint` verbatim; and include the actual file size and the allowed limit whenever the response provides them, whether as fields or inside those diagnostics. +1. Report the affected input and file; quote the tool's exact `message` and `next_step` verbatim; and include the actual file size and the allowed limit whenever the response provides them, whether as fields or inside those diagnostics. 2. State explicitly that preparation failed, the inputs are not run-ready, and no run will be offered. 3. Make no follow-up file writes: preserve the user's original file, and a case's copy of it, unchanged, and write no `inputs.prepared.json` for a case (the skill's step 5 deleted any earlier one before the call) — nothing downstream then mistakes these inputs for run-ready, and `inputs.json` keeps its local-path form because step 5 writes the prepared values only on success. 4. Continue only after the user supplies a different acceptable input or reference, or the service limit changes. -## `location: "inputs"` and the response is not a size-limit failure +## A file the walk could not read or take -Surface the exact `message` and `hint`, then follow only the recovery they support. +Surface the exact `message` and `next_step`, then follow only the recovery they support. -- **For an unreadable local file**, verify that the same file exists, resolve its path to absolute as step 5 does, and retry preparation with the file bytes unchanged. A relative path sent as-is fails this way, as `Local file cannot be read: "inputs/cv.pdf" (ENOENT)`, because the workshop resolves it against its own working directory. The correction is to the request alone, and it must not rewrite the local relative path in `inputs.json`. -- **For any other asset failure**, retry only when the documented error policy explicitly permits a recovery that preserves the asset's content and identity. +- **For an unreadable local file**, `input.file_unreadable` naming the path, verify that the same file exists, resolve its path to absolute as step 5 does, and retry preparation with the file bytes unchanged. A relative path sent as-is fails this way, as `Local file cannot be read: "inputs/cv.pdf" (ENOENT)`, because the workshop resolves it against its own working directory. The correction is to the request alone, and it must not rewrite the local relative path in `inputs.json`. +- **For a value no file input takes**, `input.invalid` naming the input, such as a `data:` URL that does not decode, fix that value in the request from the user's own file or reference. +- **For any other asset failure**, retry only when the documented error policy explicitly permits a recovery that preserves the asset's content and identity: the problem's `retry` is `"yes"`, or its `next_step` names one. The method is not at fault, so don't revalidate it: `mthds_validate` and `mthds_inputs_template` only inspect the method definition, and they will keep answering "valid" while the same asset keeps failing. -## `location: "pipe_ref"`, `"method_id"` or `"method_ref"` +## The method or its pipe did not resolve + +`method.invalid` is a closure that does not load, its `errors` the closure's faults; `request.pipe_not_found` and `request.pipe_ambiguous` are an unknown `pipe_ref` or a method that settles no entry pipe or several, with the pipes the route suggests in its `params`; `pipelex.catalog.not_found` is an id the organization does not hold; and an address that did not resolve is the runner's own problem, located at `method_ref`. This is the arm whose diagnostics the tool delegates: get the structured errors from `mthds_validate` or `mthds_inputs_template`, repair, then retry. For an address the repair is not yours to make: report it with the address and the tag. -The closure did not resolve: an invalid bundle, an unknown `pipe_ref`, an unresolvable `main_pipe`, a method id with no stored source, or an address that did not resolve. This is the arm whose diagnostics the tool delegates: get the structured errors from `mthds_validate` or `mthds_inputs_template`, repair, then retry. For an address the repair is not yours to make: report it with the address and the tag. diff --git a/pipelex/skills/pipelex-inputs/references/published-address.md b/pipelex/skills/pipelex-inputs/references/published-address.md index d4081f83..a664b1ec 100644 --- a/pipelex/skills/pipelex-inputs/references/published-address.md +++ b/pipelex/skills/pipelex-inputs/references/published-address.md @@ -1,6 +1,6 @@ # A published address -Read this at step 1 when the target is a published method's address, passed as `method_ref`, before the first call; and again when `mthds_prepare_inputs` refuses the address in one of the two ways only an address meets. An address is passed exactly as a catalog id is, so every step runs as the skill says; what follows is where an address is genuinely not like an id. +Read this at step 1 when the target is a published method's address, passed as `method_ref`, before the first call; and again when `mthds_prepare_inputs` refuses the address, before naming a cause. An address is passed exactly as a catalog id is, so every step runs as the skill says; what follows is where an address is genuinely not like an id. ## Where the inputs go @@ -8,14 +8,14 @@ The server fetches the repository at the tag and locates the package there, so t ## A template that does not validate -When `mthds_inputs_template` answers `is_valid: false` on an address, the package at that address does not validate: report `validation_errors[]` with the address and its tag, and say the fix is upstream or another tag — never a local repair of source the user does not have. +When `mthds_inputs_template` answers `is_valid: false` on an address, the package at that address does not validate: report its `errors[]` with the address and its tag, and say the fix is upstream or another tag — never a local repair of source the user does not have. -## Prepare, `input_domain` at `files`: a workshop older than the selector +## Prepare refused at `files`: a workshop older than the selector -`mthds_prepare_inputs` took `files` and `method_id` alone until the release that gave it the address, so a workshop cached from before then does not know `method_ref` — and a host that validates a call against that older tool schema drops the argument before it is ever sent. The tell is the error itself: `input_domain` located at **`files`**, saying *"Provide MTHDS files or a method_id"*, on a call that did supply a selector — the message lists what the tool accepts and leaves `method_ref` out of it. Read it as a workshop that predates the selector, not as a missing target. The same address goes on templating normally throughout, because `mthds_inputs_template` has taken it for longer — which is what makes the pair of answers the diagnosis. +`mthds_prepare_inputs` took `files` and `method_id` alone until the release that gave it the address, so a workshop cached from before then does not know `method_ref` — and a host that validates a call against that older tool schema drops the argument before it is ever sent. The tell is the error itself: located at **`files`**, saying *"Provide MTHDS files or a method_id"*, on a call that did supply a selector — the message lists what the tool accepts and leaves `method_ref` out of it. Read it as a workshop that predates the selector, not as a missing target. The same address goes on templating normally throughout, because `mthds_inputs_template` has taken it for longer — which is what makes the pair of answers the diagnosis. Give the cure with both of its conditions: the launcher fetches the newest workshop only on its next spawn, so `npx -y @pipelex/mcp@latest` changes nothing until the host restarts the server and reloads its tool schema — and a refresh only reaches the selector once a published workshop carries `method_ref` on prepare at all. Where none does yet, say that this one leg is unavailable rather than leaving them refreshing in a loop, and never fall back to submitting files you do not have. -## Prepare, class `config`: the credential first, then the deployment +## Prepare, a problem in the `account` domain: the credential, and only the credential -The skill's `config` stop applies as written: surface the `hint` verbatim and deal with the credential first, since it is the one thing the user can act on. But a by-address target has one further cause here, and nothing in the answer yet tells you which of them you met. Preparation resolves an address's signature through the run route, which refuses a published package shipping in-process Python where the deployment hosts no sandbox — and that refusal arrives in this same `config` arm wearing the deployment's authentication wording. A template call that just succeeded on the same address rules nothing out, because preparation also uploads with the key and templating never exercises that. So once the key proves good, name the other cause rather than leaving the user with a mystery: a published package can be refused by the deployment itself, and one carrying no in-process Python is not affected. +The skill's account stop applies as written: relay the `next_step` verbatim and deal with the credential first, since it is the one thing the user can act on. A template call that just succeeded on the same address rules nothing out, because preparation also uploads with the key and templating never exercises that. What the problem names is the whole cause: preparation reads an address's signature from the package's `.mthds` files alone, so the deployment's refusal of a package shipping in-process Python never reaches it. That refusal, `pipelex.deployment.custom_code_requires_sandbox`, meets the run instead, which says so in its own words. diff --git a/pipelex/skills/pipelex-inputs/references/synthetic.md b/pipelex/skills/pipelex-inputs/references/synthetic.md index 7d679b3f..f42cd330 100644 --- a/pipelex/skills/pipelex-inputs/references/synthetic.md +++ b/pipelex/skills/pipelex-inputs/references/synthetic.md @@ -52,7 +52,7 @@ Step 5 uploads the factory's files as test files of the method, so the team's fi - **A published address, or an id with a suffix (`mt_…@draft`, `mt_…@`)**: leave `kind` out. An address names no saved method, and the workshop refuses a suffixed id beside `kind`, at `method_id`. The factory's files then go up as the organization's own files. - **Mixed, with the user's own files to upload as well**: `kind` applies to every upload of a call, and the user's files are theirs, not test files. Prepare in two calls: first the inputs holding the factory's files, alone, with `kind: "test"`; then every input, without `kind`, with those inputs' prepared values in place of their paths, which the second call passes through unchanged. Write the second call's `inputs` as step 5 says, and nothing when either call fails. -- **Refused over `kind`**, as `input_domain` at `kind`, or as a `config` error tagged `kind: "role"`: no file was recorded. The first means no saved method could be named, because the folder is linked to none, its link cannot be read, was made against another API or is still the older `pipelex-method.json`, or the platform no longer holds the method; the second means the user's role may not record test files, which is no problem with the key. Prepare again without `kind`, and say in one line that the factory's files went up as the organization's own and why, in the refusal's words, relaying its hint, such as saving the method so that its folder is linked, as the user's to act on, never yours. +- **Refused over `kind`**, as `client.argument_invalid` at `kind` or at `method_id` with `params.reason` `method_not_found`, `method_being_deleted` or `version_suffix`, or as `auth.forbidden`: no file was recorded. The first means no saved method could be named, its `params.reason` saying why: the folder is linked to none, its link cannot be read, was made against another API or is still the older `pipelex-method.json`; at `method_id`, its `params.argument` naming it, the platform no longer holds the method or is erasing it, or the id carries a suffix; the last means the user's role may not record test files, which is no problem with the key. Prepare again without `kind`, and say in one line that the factory's files went up as the organization's own and why, in the refusal's words, relaying its `message`, such as saving the method so that its folder is linked, as the user's to act on, never yours. Any other refusal at `method_id`, such as `not_a_catalog_id`, is a fault of the target that dropping `kind` does not cure: the skill's stop table routes it. - **No `kind` in the answer**: a workshop older than test files drops the argument, uploads the files as the organization's own and echoes no `kind`. The inputs are run-ready all the same, so do not prepare again: say in one line that `npx -y @pipelex/mcp@latest` refreshes the workshop once the host restarts the server and reloads its tools, and that the next preparation then records test files. When the answer carries `test_method_id`, step 5's report says the files went up as test files of that method. The report gives each generated file's temporary path, for a user who wants to open it before the run, and its name among the team's files, its file name, under which it is listed with the method. diff --git a/pipelex/skills/pipelex-integrate/SKILL.md b/pipelex/skills/pipelex-integrate/SKILL.md index 6fabf66a..093256b0 100644 --- a/pipelex/skills/pipelex-integrate/SKILL.md +++ b/pipelex/skills/pipelex-integrate/SKILL.md @@ -23,7 +23,7 @@ Leave a project calling a method through one typed module, over generated types ## Requirements - **If a tool is absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Claude Code. -- **If a call returns `status: "error"` with an error of class `config`**, STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. A **403** on `mthds_codegen` is a feature gate, not a key problem. +- **If a call returns a problem in the `account` domain, or `client.unreachable`**, STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. A **403** on `mthds_codegen` is a feature gate, not a key problem. - **`mthds_list_methods`** is optional, for a method named without its id; never stop for it. ## Guards @@ -86,7 +86,7 @@ Put the generated directory and the gate script step 10 copies in the formatter' - `status: "ok"`, `is_valid: true`, `output_dir` present → written; clean when `is_current: true` with an empty `orphans[]`. - **`orphans[]` non-empty and `drifts[]` empty** → carry on to step 7 and read [references/orphans.md](references/orphans.md). Read it off the two lists, never from `is_current`; `drifts[]` is present only when non-empty, so no `drifts` is the empty case. -- **`output_dir already holds …, which this tool does not own`** → that file is the user's: never delete, move or clear it, and never offer to; choose or ask for another directory, before the call too. +- **`client.target_exists`, a file this tool does not own** → that file is the user's: never delete, move or clear it, and never offer to; choose or ask for another directory, before the call too. - anything else (`drifts[]` included) → the stops. ### 7. The sidecar @@ -137,10 +137,10 @@ What was generated and where, the target and why, the call site's signature, the | Condition | Do this | |---|---| -| invalid, unrunnable, or `pending_signatures` | STOP, nothing generated: `validation_errors[]` to `/pipelex-design` or `/pipelex-edit`, else finish it in `/pipelex-design` | -| `input_domain` at `method_ref` / `method_id` | report it in the tool's words | -| `runtime` | retry once (codegen: only if `retryable: true`, same `output_dir`), then report what landed | -| `input_domain` at `output_dir`, outside the server's directory | step 1's containment: STOP, relaunch, say what is already written | +| invalid, unrunnable, or `pending_signatures` | STOP, nothing generated: `errors[]` to `/pipelex-design` or `/pipelex-edit`, else finish it in `/pipelex-design` | +| `domain: "input"` on `method_ref` / `method_id` | report it in the tool's words | +| `retry: "yes"`, or codegen's `client.write_failed` | retry once (codegen: same `output_dir`), then report what landed | +| `outside_workspace` at `output_dir` | step 1's containment: STOP, relaunch, say what is already written | | `is_current: false`, not step 6's orphans case | report `drifts[]` verbatim and stop; commit nothing | | no signature, by address or id | STOP as the fallback reference says; never guess the output concept | | `python-structures`, its `pipelex-sdk` after step 8 unread or below the floor, templated bundle | STOP, nothing generated: [python.md](references/python.md) | diff --git a/pipelex/skills/pipelex-lab/SKILL.md b/pipelex/skills/pipelex-lab/SKILL.md index eaf65e67..7fa09dea 100644 --- a/pipelex/skills/pipelex-lab/SKILL.md +++ b/pipelex/skills/pipelex-lab/SKILL.md @@ -24,7 +24,7 @@ Start where the project stands: when `lab//` exists, read it and take up The loop needs the workshop: `/pipelex-run` starts and follows each run, and this skill reads each result with **`mthds_run_results`**, and with `mthds_run_status` and `mthds_download_artifacts`. - **If those tools are absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Claude Code. That stop comes at the loop: framing and setting up need no tool, so frame and set up, then stop before the loop. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. ## The lab directory diff --git a/pipelex/skills/pipelex-lab/references/log.md b/pipelex/skills/pipelex-lab/references/log.md index cee870fe..91d1e517 100644 --- a/pipelex/skills/pipelex-lab/references/log.md +++ b/pipelex/skills/pipelex-lab/references/log.md @@ -30,7 +30,7 @@ Failed: M3 (the memo puts the relocation clause below the medium items). Partial - **The duration** runs from the status's `created_at` to its `finished_at`. - **The score** is the Must and Must not lines passed, out of the case's Must and Must not lines. A reading an Also acceptable line allows passes the line it names, and planted facts are not scored. Partial and unscored lines count as not passed, toward the round's score and toward the pass bar, except a line the pass bar allows to be partial, which meets the bar when it is partial. - **A cut output** adds a line: "Output cut at the size cap: M4 and M6 unscored." -- **A failed run** is logged with the status and the first line of its `failure_message`, as `FAILED · …`, and scores nothing. +- **A failed run** is logged with the status and its problem's `code` and `title`, from `run_error` or the status's `error`, as `FAILED · …`, and scores nothing. - **An unfinished run** is logged as `UNFINISHED · still RUNNING after …`, with its run id, so that `/pipelex-run` can follow it later. ## A run the loop did not start diff --git a/pipelex/skills/pipelex-organize/SKILL.md b/pipelex/skills/pipelex-organize/SKILL.md index e25f3fa5..b6307faa 100644 --- a/pipelex/skills/pipelex-organize/SKILL.md +++ b/pipelex/skills/pipelex-organize/SKILL.md @@ -22,7 +22,7 @@ It is a **content-preserving transformation**: the method's semantics never chan - **`mthds_validate`** is required: this skill never reorganizes without proving the verdict is preserved. - **If the tool is absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Claude Code. Do not touch the bundle files without validation available. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never reorganize unvalidated. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. Never reorganize unvalidated. ## Guards @@ -71,14 +71,14 @@ One short summary: the layout, one line per file saying what it holds, and the p **When invoked on its own rather than by `/pipelex-design`** (whose delivery step carries both notices), end with them, since an identical verdict still rewrote every file: 1. Search the whole project for `sources.json` files carrying `"generator": "pipelex-integrate"` — `grep -rl '"pipelex-integrate"' --include=sources.json .` — which sit beside each generated tree, never beside the bundle. Keep each one whose `sources` name a `.mthds` file this change rewrote, moved or removed, or whose `templates` name a template file it changed, **or whose `bundle_dir` holds a `.mthds` file this change created** — a new file is in no `sources` map, yet the call site loads every `.mthds` file under that directory. For each, say the generated types in that directory are now stale and offer `/pipelex-integrate` to refresh them: it regenerates in place and touches the call site only if the types no longer fit it. -2. **Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a `config`-class error included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. +2. **Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. With a `template_file`, say the catalog stores no template file yet: the draft reports it missing and runs only from this directory. **Never publish here: a publish is `/pipelex-catalog`'s, on the user's request.** Leave the save to `/pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a problem in the `account` domain included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. ## Stops | Condition | Do this | |---|---| | `is_valid: false` at the baseline | never reorganize a broken library: report the verdict and point to `/pipelex-design` to fix it first | -| `status: "error"`, class `input_domain` | fix the call | -| `status: "error"`, class `runtime` | report it, and retry once before stopping | +| `status: "error"`, `domain: "input"` | fix the call | +| any other `status: "error"` | report it, after one retry when its `retry` is `"yes"` | | the candidate still differs from the baseline after two fixes of the composition | stop, leave the original layout untouched, and report the discrepancy | | the regrouping seems to need a semantic edit (a rename, a contract fix, a missing declaration) | stop and report it: that is `/pipelex-design`'s work | diff --git a/pipelex/skills/pipelex-run/SKILL.md b/pipelex/skills/pipelex-run/SKILL.md index 6102dc30..9392974c 100644 --- a/pipelex/skills/pipelex-run/SKILL.md +++ b/pipelex/skills/pipelex-run/SKILL.md @@ -26,7 +26,7 @@ This skill owns the run lifecycle: Start a run from a target and its inputs, or - **`mthds_run`**, **`mthds_run_status`** and **`mthds_run_results`** are required, and to start a run **`mthds_validate`** and **`mthds_inputs_template`** too: they keep credit from being spent on a method or inputs that cannot work. - **If the run tools are absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference](../shared/credentials.md#the-tool-is-absent) says for Claude Code. Never improvise a run id, a status or an output. -- **If a call returns `status: "error"` with an error of class `config`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. +- **If a call returns a problem in the `account` domain, or `client.unreachable`** (missing or rejected `PIPELEX_API_KEY`, unreachable API), STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from](../shared/credentials.md#where-the-key-comes-from) before saying anything more. - **`mthds_download_artifacts`**, **`mthds_list_methods`**, **`mthds_list_files`**: optional, never stop for one. ## Start a run @@ -41,7 +41,7 @@ The pipe is the declared main pipe unless the user named another: **carry its `p For a **bundle directory**, **first write a `.gitignore` holding `*` into each `runs/` in it that lacks one and whose folders hold `main_stuff.json`; add `*` to the `.gitignore` of each `inputs/` beside an `inputs.json`, and `/inputs.prepared.json` to the one beside that file, wherever the line is missing**, saying so, then one `mthds_validate` call on it. Pass the bundle directory as `method_dir`: the workshop sends its `.mthds` files and the templates their steps name, listed in `files_sent`. It refuses one outside **its own** working directory; relaunching the harness from a directory holding the bundle cures that. Inline `files` (the bundle's `.mthds` files outside `runs/`, root file first, as `{content, uri}`) are the fallback for a bundle with no template file; **for a templated one, stop and ask for that relaunch**. A workshop whose tools lack `method_dir`, or answer it *Provide MTHDS files*, is older: read [the reference](../shared/writing-mthds.md#template-files) first. For an **`mt_…` id**, the same call with `method_id` in place of `method_dir`; for an address, `method_ref`. -The bar is `is_valid: true`, `is_runnable: true` and an empty `pending_signatures`. Short of it, report the verdict and route to `/pipelex-design`, or to `/pipelex-edit` when the fix is contract-preserving; an address's verdict is reported as [its reference](references/published-address.md) says. Never run a method that did not pass. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `template_check_warning`. +The bar is `is_valid: true`, `is_runnable: true` and an empty `pending_signatures`. Short of it, report the verdict and route to `/pipelex-design`, or to `/pipelex-edit` when the fix is contract-preserving; an address's verdict is reported as [its reference](references/published-address.md) says. Never run a method that did not pass. **Report a valid verdict's `warnings`**, and read [template files](../shared/writing-mthds.md#template-files) before acting on a `pipelex.docgen.template_warning`. **A dry run is this step, shown.** A run on test files is a real run. **When the verdict carries `graph_page.written: true`, give the page's `path` before the text flow**, for a browser to open. Pass on a new page's note that a project under git may want to ignore it. A `graph_page.error` gets one line, and the verdict stands. Show the flow as numbered text: each step, what it reads and makes, where it batches or branches, and which steps call a model. For an id or an address, give the contract from the verdict's `main_pipe` instead. Say that no model ran and nothing was spent. **Then end the turn there, even when the same request asked for the real run too**: the flow is the reply, and the paid run waits for the user's go. @@ -90,7 +90,7 @@ When the inputs came from a lab case and the lab did not start this run, offer ` ### 8. A failed run is reported, then routed, never bisected -Give `failure_message` **verbatim** first, then read [failed-run.md](references/failed-run.md) before routing it; route once, and stop. When the method holds a `PipeFunc`, name it as a suspect: **`PipeFunc` is experimental on the hosted plane.** Its Python runs in a sandbox with no network access, and the feature is still in development, so a method that validates can still fail when it runs. Per-pipe bisection is not this skill's. Do not re-run a failed method with altered inputs to see what happens — that spends credit on a guess. +Give the run's `run_error` **verbatim** first, then read [failed-run.md](references/failed-run.md) before routing it; route once, and stop. When the method holds a `PipeFunc`, name it as a suspect: **`PipeFunc` is experimental on the hosted plane.** Its Python runs in a sandbox with no network access, and the feature is still in development, so a method that validates can still fail when it runs. Per-pipe bisection is not this skill's. Do not re-run a failed method with altered inputs to see what happens — that spends credit on a guess. ## Follow a run @@ -106,7 +106,7 @@ An unknown run id is reported in the tool's own words. | Condition | Do this | |---|---| -| `mthds_run`: `input_domain` at `method_id`, on a linked run | nothing was spent: read [linked-run.md](references/linked-run.md) before replying | +| `mthds_run`: `pipelex.catalog.not_found`, on a linked run | nothing was spent: read [linked-run.md](references/linked-run.md) before replying | | `mthds_download_artifacts` absent | say nothing was saved to disk and report the stored references as they came back; the run still completed | | `mthds_download_artifacts` refuses a `dir` the user named | take step 7's ignore check, then call again without it, which saves into `runs//`, and say so. A refused `dir` is not a failed save | @@ -114,4 +114,4 @@ An unknown run id is reported in the tool's own words. - [by-id.md](references/by-id.md), [published-address.md](references/published-address.md): an `mt_…` or a `method_ref` target, before the first call. - [failed-run.md](references/failed-run.md): a failed run, before routing it. -- [linked-run.md](references/linked-run.md): a linked run refused at `method_id`. +- [linked-run.md](references/linked-run.md): a linked run whose id is unknown. diff --git a/pipelex/skills/pipelex-run/references/by-id.md b/pipelex/skills/pipelex-run/references/by-id.md index fa25f1b2..7ea15209 100644 --- a/pipelex/skills/pipelex-run/references/by-id.md +++ b/pipelex/skills/pipelex-run/references/by-id.md @@ -16,15 +16,15 @@ When the user named no directory, its inputs are looked for under the bare id wh ## A method never published -A bare id of a method with no published version is refused at step 2 as `method_not_published`, and nothing is spent. Its only content is its draft: say so, carry `mt_…@draft` through every call from step 2 on, and name it in step 4's line, so the user sees that the draft is what runs. Publishing is `/pipelex-catalog`'s, on the user's request, and never a way to make a bare id run. +A bare id of a method with no published version is refused at step 2 as `pipelex.catalog.not_published`, and nothing is spent. Its only content is its draft: say so, carry `mt_…@draft` through every call from step 2 on, and name it in step 4's line, so the user sees that the draft is what runs. Publishing is `/pipelex-catalog`'s, on the user's request, and never a way to make a bare id run. ## A version the method never had -`mt_…@` for a version that does not exist is refused at `method_id` as `method_version_not_found`, and the message names the versions the method has. Nothing is spent: report it and ask which one to run. +`mt_…@` for a version that does not exist is refused as `pipelex.catalog.not_found` whose `params.resource` is `version`. Nothing is spent: report it in the tool's words and ask which one to run. ## A platform that does not resolve versions yet -Such a platform refuses `@draft` and `@`, and the hint says that a bare id reads the draft there. Report it in the tool's words; on that platform the bare id runs the draft. +Such a platform refuses `@draft` and `@`, and the problem's `message` says that a bare id reads the draft there. Report it in the tool's words; on that platform the bare id runs the draft. ## Which version ran diff --git a/pipelex/skills/pipelex-run/references/failed-run.md b/pipelex/skills/pipelex-run/references/failed-run.md index d35126b4..d5c50fb3 100644 --- a/pipelex/skills/pipelex-run/references/failed-run.md +++ b/pipelex/skills/pipelex-run/references/failed-run.md @@ -1,6 +1,10 @@ # A failed run -Read this at step 8 when a run failed, after giving its `failure_message` verbatim and before routing it. Route once, on what the failure says, and stop; the guards of the skill's step 8 hold throughout. +Read this at step 8 when a run failed, after giving its problem verbatim and before routing it. Route once, on what the failure says, and stop; the guards of the skill's step 8 hold throughout. + +The problem the run ended with is `run_error` on the failed state of `mthds_run_results`, `mthds_show_images` and `mthds_download_artifacts`, and `error` on `mthds_run_status`: its `code` (such as `run.timed_out`, `run.cancelled` or `model.unavailable`), its `domain` and `retry`, its `title`, `detail` and `next_step`, and its `errors`, the run's faults, of which `errors_omitted` counts those left out. The tool's summary renders it and closes with a support line, the run id, the code and the time the run ended: keep that line in the report, since it is what the people who run the platform find the run by. A run that stored no problem carries its status alone, and the summary says so. + +**Read the `domain` beside the wording.** `input` says the inputs must change and `method` that the method must; `runtime`, `account` and `operator` point away from both, at a provider, a quota, the organization's account or the platform, which is reported with its `next_step` rather than routed, unless the failure's own words match a row below. | What the failure says | Where it goes | |---|---| @@ -13,7 +17,7 @@ Read this at step 8 when a run failed, after giving its `failure_message` verbat A folder, like listed `files`, sends `.mthds` files and the templates their steps name, never a `.py` file, and a linked id fetches nothing: a caller-supplied source takes precedence over the stored method, which is read only when no folder or files were sent at all, so a linked run gains its history entry and nothing else, the stored `.py` files included. A bundle whose `PipeFunc` names a module of its own folder therefore has **no channel for its Python on any run of the directory**, linked or not. The path that carries it is `/pipelex-catalog`: a saved method run by its id alone has its `.mthds` and `.py` assembled into the run bundle server-side, the draft's as `mt_…@draft` and a version's once it is published. -So on a run of the directory the suspicion sharpens, but only when the failure says so. Where `failure_message` implicates finding or importing that function or its module, say that as the cause rather than offering it as one candidate among several, and give the cure: `/pipelex-catalog` saves the bundle with its Python as the method's draft, and `mt_…@draft`, run by its id alone, gets both. **Where it says anything else, route on what it says** — a missing input, a model or prompt fault, a failure upstream of the custom pipe — and leave the `PipeFunc` a suspect rather than promoting it: a bundle holding one is not evidence that it is what failed, and saving it with its Python cures nothing but that. +So on a run of the directory the suspicion sharpens, but only when the failure says so. Where the run's problem implicates finding or importing that function or its module, say that as the cause rather than offering it as one candidate among several, and give the cure: `/pipelex-catalog` saves the bundle with its Python as the method's draft, and `mt_…@draft`, run by its id alone, gets both. **Where it says anything else, route on what it says** — a missing input, a model or prompt fault, a failure upstream of the custom pipe — and leave the `PipeFunc` a suspect rather than promoting it: a bundle holding one is not evidence that it is what failed, and saving it with its Python cures nothing but that. ## A published address diff --git a/pipelex/skills/pipelex-run/references/linked-run.md b/pipelex/skills/pipelex-run/references/linked-run.md index eb68719f..35ccf212 100644 --- a/pipelex/skills/pipelex-run/references/linked-run.md +++ b/pipelex/skills/pipelex-run/references/linked-run.md @@ -1,7 +1,7 @@ -# A linked run refused at `method_id` +# A linked run whose id is unknown -Read this when `mthds_run` refuses a run that sent a linked directory as `method_dir` beside the `method_id` of its `pipelex-method.json` with an `input_domain` error located at `method_id`, before replying. Nothing was spent. +Read this when `mthds_run` refuses a run that sent a linked directory as `method_dir` beside the `method_id` of its `pipelex-method.json` with `pipelex.catalog.not_found`, before replying. Nothing was spent. -A linkage id the plane does not know refuses the run, and on a run that sent a folder beside the id, that location is the discriminator rather than a coincidence: a rejected payload or a refused execution locus locates at `method_dir`, or at `files` when the files were listed, so only the unknown-method arm lands at `method_id`, and its hint says the id is not visible to the API key's organization. The catalog is org-scoped, so a link made with another organization's key, or against another plane, reads exactly like a deleted method. +A linkage id the plane does not know refuses the run, and on a run that sent a folder beside the id, the problem's `code` is the discriminator rather than its wording: a rejected payload or a refused execution locus answers with a code of its own, located at `method_dir`, or at `files` when the files were listed, so only the unknown method answers `pipelex.catalog.not_found`, its `params` naming the id the API key's organization does not hold. The catalog is org-scoped, so a link made with another organization's key, or against another plane, reads exactly like a deleted method. Report it with the `api_host` the link file records — that is what makes it diagnosable — and offer the same run **without** the id: it runs the very same bundle and loses only the history filing. Do not go looking for the bundle; the bundle was never in question. diff --git a/pipelex/skills/pipelex-run/references/published-address.md b/pipelex/skills/pipelex-run/references/published-address.md index 61555c65..68ebef69 100644 --- a/pipelex/skills/pipelex-run/references/published-address.md +++ b/pipelex/skills/pipelex-run/references/published-address.md @@ -4,7 +4,7 @@ Read this at step 1 when the target is a published method's address, passed as ` ## It pairs with nothing -An address is a complete run source, so **an address pairs with nothing**: a `method_dir`, `files` or a `method_id` beside it is refused with an `input_domain` error before anything runs. Every call carries the `method_ref` alone. +An address is a complete run source, so **an address pairs with nothing**: a `method_dir`, `files` or a `method_id` beside it is refused as `client.argument_invalid` before anything runs. Every call carries the `method_ref` alone. ## It floats without a tag diff --git a/pipelex/skills/pipelex-synthetic-inputs/references/photograph.md b/pipelex/skills/pipelex-synthetic-inputs/references/photograph.md index 0d8d64e2..09ff5219 100644 --- a/pipelex/skills/pipelex-synthetic-inputs/references/photograph.md +++ b/pipelex/skills/pipelex-synthetic-inputs/references/photograph.md @@ -58,7 +58,7 @@ Its description says what changes (the side, the angle, the damage) and repeats **A room seen from two places keeps its materials and loses its walls.** The model draws what the description puts on the left and the right of the frame, but as a view straight down the room, wherever the photographer was said to stand. A second view "from the opposite corner", with the windows on its left and the fireplace on its right, therefore puts the two on facing walls, when the first photograph had them side by side. Write the room's plan before the first description, naming what is on each wall, and describe the second view by the wall it faces and what stands on the walls to its left and right: "facing the fireplace wall, the two windows on the right-hand wall, a bare wall on the left". -Follow each run with `mthds_run_status` at the hint it gives, then `mthds_run_results` once it is terminal. A failed run is reported with its `failure_message` verbatim, and that photograph is left without a path; do not retry it with a reworded description on a guess. +Follow each run with `mthds_run_status` at the hint it gives, then `mthds_run_results` once it is terminal. A failed run is reported with its problem, `run_error` (`error` on the status), verbatim, and that photograph is left without a path; do not retry it with a reworded description on a guess. ## 3. Save it diff --git a/pipelex/skills/shared/credentials.md b/pipelex/skills/shared/credentials.md index a8bfa628..36106780 100644 --- a/pipelex/skills/shared/credentials.md +++ b/pipelex/skills/shared/credentials.md @@ -1,6 +1,6 @@ # Connecting the Pipelex workshop, and its key -Read this when an MCP-backed skill sends you here: because one of the plugin's `mthds_*` tools is absent from the session, or because a call returned a `config`-class error about the API key. It says what to tell the user on Claude Code, and nothing more: whether the skill stops there or carries on without the tool is the skill's own rule, which this file changes in neither direction. +Read this when an MCP-backed skill sends you here: because one of the plugin's `mthds_*` tools is absent from the session, or because a call returned a problem about the API key, `auth.missing_credential`, `auth.invalid_credential` or `auth.credential_expired`. It says what to tell the user on Claude Code, and nothing more: whether the skill stops there or carries on without the tool is the skill's own rule, which this file changes in neither direction. ## The tool is absent @@ -12,6 +12,8 @@ The Pipelex connector's `pipelex_*` tools, when the session has them, belong to The server authenticates to the API with **`PIPELEX_API_KEY`**. It uses the key its host hands it, which on Claude Code is the key entered in the **plugin configuration** when the plugin was enabled, kept in the OS keychain and exported for the server by its launcher, or else a `PIPELEX_API_KEY` exported in the shell Claude Code starts from, which Claude Desktop, launched from the desktop, never has. When the host hands it none, it reads the key saved in `~/.pipelex/.env`, or in the `.env` of `PIPELEX_HOME` when that variable reaches it, afresh on every call, so a key saved while the session runs is used from the next call with no restart. -So a `config`-class error about the key is answered by the workshop's login, which the user runs themselves in a terminal: **`npx -y @pipelex/mcp@latest login`** opens the browser on app.pipelex.com, mints a key for the account's current organization and saves it in that file (`--paste` reads one created in the app instead, for a machine with no browser). The pipelex CLI's `pipelex login` saves to the same file, so a key it saved counts too. When the error's hint says the host's own key was refused, the saved one is never consulted until that key is removed or replaced in the plugin's configuration or the shell, whichever holds it. Never read that file or print a key yourself. +So a problem about the key is answered by the workshop's login, which the user runs themselves in a terminal: **`npx -y @pipelex/mcp@latest login`** opens the browser on app.pipelex.com, mints a key for the account's current organization and saves it in that file (`--paste` reads one created in the app instead, for a machine with no browser). The pipelex CLI's `pipelex login` saves to the same file, so a key it saved counts too. When the tool's summary says the host's own key was refused, the saved one is never consulted until that key is removed or replaced in the plugin's configuration or the shell, whichever holds it. Never read that file or print a key yourself. The plugin's validation hook reads `PIPELEX_API_KEY` from the plugin configuration or the shell alone, never from that file, so with only a saved key it still lints and formats each edit but skips validating it against the API. + +`auth.forbidden` is not about the key: the platform refused the action for the role the key's owner holds in the organization, and its `detail` names that role and what the action needs. No login or new key changes a role, so relay it as it came and never send the user to the login for it. diff --git a/pipelex/skills/shared/writing-mthds.md b/pipelex/skills/shared/writing-mthds.md index 0908d577..308265d5 100644 --- a/pipelex/skills/shared/writing-mthds.md +++ b/pipelex/skills/shared/writing-mthds.md @@ -704,7 +704,7 @@ A dry run composes the document for real against mock inputs, which checks the t **The catalog stores no template file yet**: `mthds_save_method` takes `.mthds` and `.py` files alone, so a saved method whose step names a template file does not load by its id, while its directory still validates and runs as `method_dir`. -**A `template_check_warning` in a valid verdict's `warnings`** is the template check's finding in the file a step names, located by its `pipe_code`, `template_file` and `template_location`, such as a field that matches no input of the step. It never changes `is_valid`, but the printed file may show it. A skill that writes the method fixes it in the template it wrote, or in the step, and validates again; a template the user supplied is theirs, so name the finding and ask before changing it. A skill that only reads or runs the method reports it with the verdict. +**A `pipelex.docgen.template_warning` in a valid verdict's `warnings`** is the template check's finding in the file a step names, a problem item located at the step's pipe (`location.pipe`) whose `params` carry `template_file`, the file as the step names it, and `template_location`, where in the file, such as a field that matches no input of the step. It never changes `is_valid`, but the printed file may show it. A skill that writes the method fixes it in the template it wrote, or in the step, and validates again; a template the user supplied is theirs, so name the finding and ask before changing it. A skill that only reads or runs the method reports it with the verdict. ### PipeFunc — call a Python function of the method's folder diff --git a/skills/pipelex-catalog/references/conflict.md b/skills/pipelex-catalog/references/conflict.md index fb2a1c31..47aed0e5 100644 --- a/skills/pipelex-catalog/references/conflict.md +++ b/skills/pipelex-catalog/references/conflict.md @@ -1,6 +1,6 @@ # When a save is refused at `expected_updated_at`, or a version is restored -Read this when `mthds_save_method` answers an `input_domain` error at `expected_updated_at`, or before saving a directory that holds a pulled version because the user asked to restore it, before replying to the user. A refusal writes nothing, not the draft and not the link. A conflict names the draft's current `updated_at` and the token the save was sent under; a save refused because the directory holds a pulled version names the token a restore takes. Only the draft is at stake: published versions never change, and nothing below publishes. +Read this when `mthds_save_method` answers a problem at `expected_updated_at`, or before saving a directory that holds a pulled version because the user asked to restore it, before replying to the user. A refusal writes nothing, not the draft and not the link. A conflict is `pipelex.catalog.update_conflict`, whose `message` names the draft's current `updated_at` and the token the save was sent under; a save refused because the directory holds a pulled version is `client.argument_invalid` with `params.reason` `version_pulled`, whose `message` names the token a restore takes. Only the draft is at stake: published versions never change, and nothing below publishes. **First, does the directory hold a pulled version?** When `pipelex-method.json` records a `synced_version`, or the refusal says the directory holds one, the files here are version n, pulled to read or to start over from, perhaps edited since, and saving them replaces the draft with them: a restore. Unless the user asked for it, say so and give the two ways forward: pull the draft back into this directory to go on working on the draft, or restore, which makes these files, edits included, the draft. The pull writes over the version's untouched files freely, since the catalog stores them, and refuses a file edited since the version pull: those edits survive only a restore or a copy the user moves aside first, so never answer that refusal with `overwrite: true` without saying the edits are lost. A restore, made only on the user's request or an explicit yes, is the same call with `expected_updated_at` set to the `updated_at` the version pull reported, which the link records as `synced_updated_at` and the refusal names too, and `python` as the version's `.py` files, or `[]` when it has none, since an omitted `python` keeps the draft's. That token is the draft as the pull found it, so a draft saved since then refuses the restore: that refusal is a conflict, answered as the last paragraph and its two ways forward say, and saving over it is this restore sent with the draft's current `updated_at`, on the user's yes once they have seen both timestamps. Never take the draft's current `updated_at` for a restore before that refusal, from a pull or from anywhere else: it would restore over a draft nobody here has seen. A restore publishes nothing; a publish of the restored draft is a request of its own. diff --git a/skills/pipelex-catalog/references/unknown-id.md b/skills/pipelex-catalog/references/unknown-id.md index 2dd255c2..80112b26 100644 --- a/skills/pipelex-catalog/references/unknown-id.md +++ b/skills/pipelex-catalog/references/unknown-id.md @@ -1,15 +1,19 @@ -# An error at `method_id` +# A miss, or a problem at `method_id` -Read this when `mthds_save_method`, `mthds_publish_method` or a pull's `mthds_get_method` answers an `input_domain` error at `method_id`, before concluding anything about the directory's link. The skill's guard on the link holds throughout: it is removed only on the user's yes. +Read this when `mthds_save_method`, `mthds_publish_method` or a pull's `mthds_get_method` answers `pipelex.catalog.not_found`, or another problem located at `method_id`, before concluding anything about the directory's link. The skill's guard on the link holds throughout: it is removed only on the user's yes. -An unknown `method_id` comes back at that location, and so do several other faults: a payload the platform rejected, an organization-context failure, and the workshop's own refusal when this directory's link names a *different* method from the id being saved. **The location alone never tells them apart**, so read the message and the hint before doing anything: only the not-found answer names `pipelex-method.json` and the `api_host` and explains that the catalog is org-scoped, so a method from another organization reads exactly like a miss. Anything else is a different fault: the link is not dead, it stays where it is, and the fix is to the call. +Several faults land on the same id, and **the problem's `code` tells them apart**, never its location or its wording. Only `pipelex.catalog.not_found` whose `params.resource` is `method` is a miss: the catalog is org-scoped, so a method from another organization reads exactly like one. Anything else is a different fault, the link is not dead, it stays where it is, and the fix is to the call: -**A version suffix is refused there too, and is not a miss.** A save and a publish take the bare id, since both act on the draft, so `mt_…@` is refused before anything is sent: call again with the bare id, and to publish an old version's content again, pull that version, restore it as the draft and publish that. A pull of a version the method never had names the versions it has: offer one of those, or the draft. +- `client.target_exists` at `method_id` is the workshop's own refusal when this directory's link names a *different* method from the id being saved. Its `message` names both and what to pass instead. +- `client.argument_invalid` at `method_id` is a call the workshop refused before sending it, its `params.reason` saying why. **A version suffix is refused there, as `version_suffix`, and is not a miss.** A save and a publish take the bare id, since both act on the draft, so `mt_…@` is refused before anything is sent: call again with the bare id, and to publish an old version's content again, pull that version, restore it as the draft and publish that. +- `pipelex.catalog.not_found` whose `params.resource` is `version` is a pull of a version the method never had. Its `message` names the versions it has: offer one of those, or the draft. +- `method.package_invalid` with `params.reason` `empty_tree` is a pull of a method whose stored source holds no file yet. It is not a miss: relay it as the pull's report step says. +- Any other code, such as a payload the platform rejected or a failure of the organization's context, is relayed with its `detail` and `next_step`. -**A save's miss is checked against a read first.** When a save answers that the id is not visible, call `mthds_get_method` on the same bare id without `output_dir`: when it reads the method, the id is alive and this platform has no draft save yet, a platform older than drafts. Say so and stop; the link stays and nothing here creates a method. +**A save's miss is checked against a read first.** When a save answers `pipelex.catalog.not_found`, call `mthds_get_method` on the same bare id without `output_dir`: when it reads the method, the id is alive and this platform has no draft save yet, a platform older than drafts. Say so and stop; the link stays and nothing here creates a method. -When the hint does say the id is not visible, and a read does not find it either, report it **with the `api_host` the link file records** — that is what makes it diagnosable: the link was made against another plane, or with another organization's key. +When a read does not find it either, report the miss **with the `api_host` the link file records** — that is what makes it diagnosable: the link was made against another plane, or with another organization's key. Then offer to save the directory as a **new** method. That needs the stale link gone first: the workshop refuses a create into a directory another link claims, rather than minting a duplicate nobody can delete. So ask, and on a yes remove `pipelex-method.json` and run the create, which writes a fresh link. -**A pull or a publish has no link to judge.** When the error came from `mthds_get_method` or `mthds_publish_method`, nothing was written or published and nothing on disk is touched. An empty stored source answers at the same location and is not a miss: relay it as the pull's report step says. Otherwise relay the answer and its hint, and when the hint says the id is not visible, say that a method saved from another organization, or on another plane, reads exactly like a miss, and offer to find the method by name, as the skill's "List and find" says. +**A pull or a publish has no link to judge.** When the problem came from `mthds_get_method` or `mthds_publish_method`, nothing was written or published and nothing on disk is touched. Relay its `detail` and `next_step`, and on a miss say that a method saved from another organization, or on another plane, reads exactly like one, and offer to find the method by name, as the skill's "List and find" says. diff --git a/skills/pipelex-design/references/stepwise.md b/skills/pipelex-design/references/stepwise.md index 9604046c..b604c77a 100644 --- a/skills/pipelex-design/references/stepwise.md +++ b/skills/pipelex-design/references/stepwise.md @@ -48,7 +48,7 @@ Given pending signature `S` with frozen `inputs`, `output`, `description`, and ` The new file bounds the ordinary fix: - **Contract mismatch:** conform the definition to the frozen header. If the header itself is wrong, that is a propagating contract change; pause and revise the parent region deliberately rather than silently changing the header. -- **Other semantic errors:** use `validation_errors[]`, the Markdown locators, and the relevant section of the authoring reference; fix the added file and re-validate. +- **Other semantic errors:** use the verdict's `errors[]`, each item's `code`, `detail` and `location`, and the relevant section of the authoring reference; fix the added file and re-validate. ## Stopping early diff --git a/skills/pipelex-explain/references/not-on-disk.md b/skills/pipelex-explain/references/not-on-disk.md index d2c8a31a..39b19058 100644 --- a/skills/pipelex-explain/references/not-on-disk.md +++ b/skills/pipelex-explain/references/not-on-disk.md @@ -6,7 +6,7 @@ The two targets part company on ownership rather than convenience. **A catalog i ## A catalog id: read it in full -Call `mthds_get_method` with the `method_id`, as the skill's step 1 says. The `files` it returns are explained **exactly as a bundle on disk is**, through the skill's steps 1 to 5, with the returned contents standing in for the files you would have read. The verdict of step 3 is one `mthds_validate` call naming the content that was read: `mt_…@draft` when the result's `version` is `draft`, and `mt_…@` for version n. A platform that does not resolve versions yet refuses the suffix, with a hint saying that a bare id reads the draft there: validate the bare id then, which reads the same stored content on that platform, and say so. +Call `mthds_get_method` with the `method_id`, as the skill's step 1 says. The `files` it returns are explained **exactly as a bundle on disk is**, through the skill's steps 1 to 5, with the returned contents standing in for the files you would have read. The verdict of step 3 is one `mthds_validate` call naming the content that was read: `mt_…@draft` when the result's `version` is `draft`, and `mt_…@` for version n. A platform that does not resolve versions yet refuses the suffix, the problem's `message` saying that a bare id reads the draft there: validate the bare id then, which reads the same stored content on that platform, and say so. **A bare id reads the draft here and the latest published version everywhere else.** `mthds_get_method` reads a bare id's draft, which is what the next save replaces, while a validation, an inputs template or a run of the same bare id reads the latest published version, what the method's callers run. So never validate a draft's source under the bare id, and say which content the explanation is of. The result's `publish_state` says how the two stand: `draft_ahead` means callers of the bare id run version `latest_version`, which differs from what you explained, so say so and offer to explain `mt_…@`; `draft_unchanged` means they run what you explained; `never_published` means a bare id runs nothing yet. @@ -18,7 +18,7 @@ Three things about the returned set are worth knowing before you describe it: ## Without `mthds_get_method` -When the other tools answer and `mthds_get_method` does not, read the id at contract level exactly as an address is read below, with `method_id` as the selector, and say that the source was not read rather than implying there was none to read. A bare id there is the latest published version, and one never published is refused as `method_not_published`, whose draft `mt_…@draft` can be read instead; say which you read. **The cause is a local workshop that predates the tool**, which `npx -y @pipelex/mcp@latest` refreshes; say so. The Pipelex connector's `pipelex_*` tools, when the session has them too, belong to a different server with no tool of this name, so they neither cause this nor stand in for the workshop. +When the other tools answer and `mthds_get_method` does not, read the id at contract level exactly as an address is read below, with `method_id` as the selector, and say that the source was not read rather than implying there was none to read. A bare id there is the latest published version, and one never published is refused as `pipelex.catalog.not_published`, whose draft `mt_…@draft` can be read instead; say which you read. **The cause is a local workshop that predates the tool**, which `npx -y @pipelex/mcp@latest` refreshes; say so. The Pipelex connector's `pipelex_*` tools, when the session has them too, belong to a different server with no tool of this name, so they neither cause this nor stand in for the workshop. ## A published address: its contract @@ -31,5 +31,5 @@ When the other tools answer and `mthds_get_method` does not, read the id at cont A published address has no source to fall back on, and neither has an id read at contract level, so these verdicts are said rather than filled in. An id read in full still has its source. - **The verdict is positive but carries no `main_pipe`.** The method settles no entry pipe, the contract did not come back whole, or the workshop predates the field — the same three causes `/pipelex-integrate` names, and the one-line signature in the text summary is missing in all three. Say the verdict was positive and that it carries no signature to describe the contract with, and name which of the three the tool's own message points to. -- **The verdict is `is_valid: false`.** There is no `main_pipe` on an invalid verdict and `mthds_inputs_template` answers with `validation_errors[]` rather than shapes, so nothing about the method is readable **from the verdict** — though for an id read in full the source still is, and an invalid stored method is worth explaining from its source with the errors beside it. Report the errors as they came back. **Do not route a remote target to `/pipelex-edit` or `/pipelex-design`**: a stored method is fixed where it is edited — `/pipelex-catalog` is what brings it to disk first — and a published address is fixed in the repository it names. -- **The id is refused rather than read.** An unknown id and a method whose stored source is empty both arrive as `input_domain` at `method_id`: the first says no such method is visible to the API key's organization, which a method from another organization reads exactly like; the second says the row exists and holds no source yet. Give the one the tool gave, as the skill's stop table says. +- **The verdict is `is_valid: false`.** There is no `main_pipe` on an invalid verdict and `mthds_inputs_template` answers with `errors[]` rather than shapes, so nothing about the method is readable **from the verdict** — though for an id read in full the source still is, and an invalid stored method is worth explaining from its source with the errors beside it. Report the errors as they came back. **Do not route a remote target to `/pipelex-edit` or `/pipelex-design`**: a stored method is fixed where it is edited — `/pipelex-catalog` is what brings it to disk first — and a published address is fixed in the repository it names. +- **The id is refused rather than read.** An unknown id and a method whose stored source is empty are told apart by the problem's `code`: the first is `pipelex.catalog.not_found`, no such method visible to the API key's organization, which a method from another organization reads exactly like; the second is `method.package_invalid` at `method_id`, the row existing and holding no source yet. Give the one the tool gave, as the skill's stop table says. diff --git a/skills/pipelex-inputs/references/prepare-errors.md b/skills/pipelex-inputs/references/prepare-errors.md index 11396395..d6f6919d 100644 --- a/skills/pipelex-inputs/references/prepare-errors.md +++ b/skills/pipelex-inputs/references/prepare-errors.md @@ -1,25 +1,27 @@ # When preparation fails -Read this when `mthds_prepare_inputs` answers `status: "error"` with class `input_domain` located at `inputs`, `pipe_ref`, `method_id` or `method_ref`, before replying to the user or retrying. Unlike `mthds_inputs_template`, the tool has no produced-invalid arm: it never returns a `validation_errors[]` list. **Read the error's `location` first**, because the causes need opposite repairs. The skill's file-fidelity guard holds throughout: nothing here is a reason to transform, derive or substitute a file, or to retry with one. +Read this when `mthds_prepare_inputs` answers `status: "error"` with a problem the inputs or the method's resolution must fix (its `domain` is `input` or `method`), before replying to the user or retrying. Unlike `mthds_inputs_template`, the tool has no produced-invalid arm: it never returns a verdict with `errors[]` of its own. **Read the problem's `code` first**, because the causes need opposite repairs; the location and the wording never tell them apart. A refusal of `kind` is not this file's: on a call that passed `kind: "test"`, `client.argument_invalid` whose `params.argument` is `kind`, or is `method_id` with `params.reason` `method_not_found`, `method_being_deleted` or `version_suffix`, and `auth.forbidden` are about recording test files, which the skill answers where it passes `kind`. The skill's file-fidelity guard holds throughout: nothing here is a reason to transform, derive or substitute a file, or to retry with one. -## `location: "inputs"` and the response reports a storage size limit +## `upload_too_large`: a file over the storage size limit -This is a terminal branch for the current preparation attempt. +The workshop refuses a file over the upload ceiling before anything is sent, as `client.argument_invalid` at `inputs` whose `params.reason` is `upload_too_large`. This is a terminal branch for the current preparation attempt. -1. Report the affected input and file; quote the tool's exact `message` and `hint` verbatim; and include the actual file size and the allowed limit whenever the response provides them, whether as fields or inside those diagnostics. +1. Report the affected input and file; quote the tool's exact `message` and `next_step` verbatim; and include the actual file size and the allowed limit whenever the response provides them, whether as fields or inside those diagnostics. 2. State explicitly that preparation failed, the inputs are not run-ready, and no run will be offered. 3. Make no follow-up file writes: preserve the user's original file, and a case's copy of it, unchanged, and write no `inputs.prepared.json` for a case (the skill's step 5 deleted any earlier one before the call) — nothing downstream then mistakes these inputs for run-ready, and `inputs.json` keeps its local-path form because step 5 writes the prepared values only on success. 4. Continue only after the user supplies a different acceptable input or reference, or the service limit changes. -## `location: "inputs"` and the response is not a size-limit failure +## A file the walk could not read or take -Surface the exact `message` and `hint`, then follow only the recovery they support. +Surface the exact `message` and `next_step`, then follow only the recovery they support. -- **For an unreadable local file**, verify that the same file exists, resolve its path to absolute as step 5 does, and retry preparation with the file bytes unchanged. A relative path sent as-is fails this way, as `Local file cannot be read: "inputs/cv.pdf" (ENOENT)`, because the workshop resolves it against its own working directory. The correction is to the request alone, and it must not rewrite the local relative path in `inputs.json`. -- **For any other asset failure**, retry only when the documented error policy explicitly permits a recovery that preserves the asset's content and identity. +- **For an unreadable local file**, `input.file_unreadable` naming the path, verify that the same file exists, resolve its path to absolute as step 5 does, and retry preparation with the file bytes unchanged. A relative path sent as-is fails this way, as `Local file cannot be read: "inputs/cv.pdf" (ENOENT)`, because the workshop resolves it against its own working directory. The correction is to the request alone, and it must not rewrite the local relative path in `inputs.json`. +- **For a value no file input takes**, `input.invalid` naming the input, such as a `data:` URL that does not decode, fix that value in the request from the user's own file or reference. +- **For any other asset failure**, retry only when the documented error policy explicitly permits a recovery that preserves the asset's content and identity: the problem's `retry` is `"yes"`, or its `next_step` names one. The method is not at fault, so don't revalidate it: `mthds_validate` and `mthds_inputs_template` only inspect the method definition, and they will keep answering "valid" while the same asset keeps failing. -## `location: "pipe_ref"`, `"method_id"` or `"method_ref"` +## The method or its pipe did not resolve + +`method.invalid` is a closure that does not load, its `errors` the closure's faults; `request.pipe_not_found` and `request.pipe_ambiguous` are an unknown `pipe_ref` or a method that settles no entry pipe or several, with the pipes the route suggests in its `params`; `pipelex.catalog.not_found` is an id the organization does not hold; and an address that did not resolve is the runner's own problem, located at `method_ref`. This is the arm whose diagnostics the tool delegates: get the structured errors from `mthds_validate` or `mthds_inputs_template`, repair, then retry. For an address the repair is not yours to make: report it with the address and the tag. -The closure did not resolve: an invalid bundle, an unknown `pipe_ref`, an unresolvable `main_pipe`, a method id with no stored source, or an address that did not resolve. This is the arm whose diagnostics the tool delegates: get the structured errors from `mthds_validate` or `mthds_inputs_template`, repair, then retry. For an address the repair is not yours to make: report it with the address and the tag. diff --git a/skills/pipelex-inputs/references/published-address.md b/skills/pipelex-inputs/references/published-address.md index d4081f83..a664b1ec 100644 --- a/skills/pipelex-inputs/references/published-address.md +++ b/skills/pipelex-inputs/references/published-address.md @@ -1,6 +1,6 @@ # A published address -Read this at step 1 when the target is a published method's address, passed as `method_ref`, before the first call; and again when `mthds_prepare_inputs` refuses the address in one of the two ways only an address meets. An address is passed exactly as a catalog id is, so every step runs as the skill says; what follows is where an address is genuinely not like an id. +Read this at step 1 when the target is a published method's address, passed as `method_ref`, before the first call; and again when `mthds_prepare_inputs` refuses the address, before naming a cause. An address is passed exactly as a catalog id is, so every step runs as the skill says; what follows is where an address is genuinely not like an id. ## Where the inputs go @@ -8,14 +8,14 @@ The server fetches the repository at the tag and locates the package there, so t ## A template that does not validate -When `mthds_inputs_template` answers `is_valid: false` on an address, the package at that address does not validate: report `validation_errors[]` with the address and its tag, and say the fix is upstream or another tag — never a local repair of source the user does not have. +When `mthds_inputs_template` answers `is_valid: false` on an address, the package at that address does not validate: report its `errors[]` with the address and its tag, and say the fix is upstream or another tag — never a local repair of source the user does not have. -## Prepare, `input_domain` at `files`: a workshop older than the selector +## Prepare refused at `files`: a workshop older than the selector -`mthds_prepare_inputs` took `files` and `method_id` alone until the release that gave it the address, so a workshop cached from before then does not know `method_ref` — and a host that validates a call against that older tool schema drops the argument before it is ever sent. The tell is the error itself: `input_domain` located at **`files`**, saying *"Provide MTHDS files or a method_id"*, on a call that did supply a selector — the message lists what the tool accepts and leaves `method_ref` out of it. Read it as a workshop that predates the selector, not as a missing target. The same address goes on templating normally throughout, because `mthds_inputs_template` has taken it for longer — which is what makes the pair of answers the diagnosis. +`mthds_prepare_inputs` took `files` and `method_id` alone until the release that gave it the address, so a workshop cached from before then does not know `method_ref` — and a host that validates a call against that older tool schema drops the argument before it is ever sent. The tell is the error itself: located at **`files`**, saying *"Provide MTHDS files or a method_id"*, on a call that did supply a selector — the message lists what the tool accepts and leaves `method_ref` out of it. Read it as a workshop that predates the selector, not as a missing target. The same address goes on templating normally throughout, because `mthds_inputs_template` has taken it for longer — which is what makes the pair of answers the diagnosis. Give the cure with both of its conditions: the launcher fetches the newest workshop only on its next spawn, so `npx -y @pipelex/mcp@latest` changes nothing until the host restarts the server and reloads its tool schema — and a refresh only reaches the selector once a published workshop carries `method_ref` on prepare at all. Where none does yet, say that this one leg is unavailable rather than leaving them refreshing in a loop, and never fall back to submitting files you do not have. -## Prepare, class `config`: the credential first, then the deployment +## Prepare, a problem in the `account` domain: the credential, and only the credential -The skill's `config` stop applies as written: surface the `hint` verbatim and deal with the credential first, since it is the one thing the user can act on. But a by-address target has one further cause here, and nothing in the answer yet tells you which of them you met. Preparation resolves an address's signature through the run route, which refuses a published package shipping in-process Python where the deployment hosts no sandbox — and that refusal arrives in this same `config` arm wearing the deployment's authentication wording. A template call that just succeeded on the same address rules nothing out, because preparation also uploads with the key and templating never exercises that. So once the key proves good, name the other cause rather than leaving the user with a mystery: a published package can be refused by the deployment itself, and one carrying no in-process Python is not affected. +The skill's account stop applies as written: relay the `next_step` verbatim and deal with the credential first, since it is the one thing the user can act on. A template call that just succeeded on the same address rules nothing out, because preparation also uploads with the key and templating never exercises that. What the problem names is the whole cause: preparation reads an address's signature from the package's `.mthds` files alone, so the deployment's refusal of a package shipping in-process Python never reaches it. That refusal, `pipelex.deployment.custom_code_requires_sandbox`, meets the run instead, which says so in its own words. diff --git a/skills/pipelex-inputs/references/synthetic.md b/skills/pipelex-inputs/references/synthetic.md index 7d679b3f..f42cd330 100644 --- a/skills/pipelex-inputs/references/synthetic.md +++ b/skills/pipelex-inputs/references/synthetic.md @@ -52,7 +52,7 @@ Step 5 uploads the factory's files as test files of the method, so the team's fi - **A published address, or an id with a suffix (`mt_…@draft`, `mt_…@`)**: leave `kind` out. An address names no saved method, and the workshop refuses a suffixed id beside `kind`, at `method_id`. The factory's files then go up as the organization's own files. - **Mixed, with the user's own files to upload as well**: `kind` applies to every upload of a call, and the user's files are theirs, not test files. Prepare in two calls: first the inputs holding the factory's files, alone, with `kind: "test"`; then every input, without `kind`, with those inputs' prepared values in place of their paths, which the second call passes through unchanged. Write the second call's `inputs` as step 5 says, and nothing when either call fails. -- **Refused over `kind`**, as `input_domain` at `kind`, or as a `config` error tagged `kind: "role"`: no file was recorded. The first means no saved method could be named, because the folder is linked to none, its link cannot be read, was made against another API or is still the older `pipelex-method.json`, or the platform no longer holds the method; the second means the user's role may not record test files, which is no problem with the key. Prepare again without `kind`, and say in one line that the factory's files went up as the organization's own and why, in the refusal's words, relaying its hint, such as saving the method so that its folder is linked, as the user's to act on, never yours. +- **Refused over `kind`**, as `client.argument_invalid` at `kind` or at `method_id` with `params.reason` `method_not_found`, `method_being_deleted` or `version_suffix`, or as `auth.forbidden`: no file was recorded. The first means no saved method could be named, its `params.reason` saying why: the folder is linked to none, its link cannot be read, was made against another API or is still the older `pipelex-method.json`; at `method_id`, its `params.argument` naming it, the platform no longer holds the method or is erasing it, or the id carries a suffix; the last means the user's role may not record test files, which is no problem with the key. Prepare again without `kind`, and say in one line that the factory's files went up as the organization's own and why, in the refusal's words, relaying its `message`, such as saving the method so that its folder is linked, as the user's to act on, never yours. Any other refusal at `method_id`, such as `not_a_catalog_id`, is a fault of the target that dropping `kind` does not cure: the skill's stop table routes it. - **No `kind` in the answer**: a workshop older than test files drops the argument, uploads the files as the organization's own and echoes no `kind`. The inputs are run-ready all the same, so do not prepare again: say in one line that `npx -y @pipelex/mcp@latest` refreshes the workshop once the host restarts the server and reloads its tools, and that the next preparation then records test files. When the answer carries `test_method_id`, step 5's report says the files went up as test files of that method. The report gives each generated file's temporary path, for a user who wants to open it before the run, and its name among the team's files, its file name, under which it is listed with the method. diff --git a/skills/pipelex-lab/references/log.md b/skills/pipelex-lab/references/log.md index cee870fe..91d1e517 100644 --- a/skills/pipelex-lab/references/log.md +++ b/skills/pipelex-lab/references/log.md @@ -30,7 +30,7 @@ Failed: M3 (the memo puts the relocation clause below the medium items). Partial - **The duration** runs from the status's `created_at` to its `finished_at`. - **The score** is the Must and Must not lines passed, out of the case's Must and Must not lines. A reading an Also acceptable line allows passes the line it names, and planted facts are not scored. Partial and unscored lines count as not passed, toward the round's score and toward the pass bar, except a line the pass bar allows to be partial, which meets the bar when it is partial. - **A cut output** adds a line: "Output cut at the size cap: M4 and M6 unscored." -- **A failed run** is logged with the status and the first line of its `failure_message`, as `FAILED · …`, and scores nothing. +- **A failed run** is logged with the status and its problem's `code` and `title`, from `run_error` or the status's `error`, as `FAILED · …`, and scores nothing. - **An unfinished run** is logged as `UNFINISHED · still RUNNING after …`, with its run id, so that `/pipelex-run` can follow it later. ## A run the loop did not start diff --git a/skills/pipelex-run/references/by-id.md b/skills/pipelex-run/references/by-id.md index fa25f1b2..7ea15209 100644 --- a/skills/pipelex-run/references/by-id.md +++ b/skills/pipelex-run/references/by-id.md @@ -16,15 +16,15 @@ When the user named no directory, its inputs are looked for under the bare id wh ## A method never published -A bare id of a method with no published version is refused at step 2 as `method_not_published`, and nothing is spent. Its only content is its draft: say so, carry `mt_…@draft` through every call from step 2 on, and name it in step 4's line, so the user sees that the draft is what runs. Publishing is `/pipelex-catalog`'s, on the user's request, and never a way to make a bare id run. +A bare id of a method with no published version is refused at step 2 as `pipelex.catalog.not_published`, and nothing is spent. Its only content is its draft: say so, carry `mt_…@draft` through every call from step 2 on, and name it in step 4's line, so the user sees that the draft is what runs. Publishing is `/pipelex-catalog`'s, on the user's request, and never a way to make a bare id run. ## A version the method never had -`mt_…@` for a version that does not exist is refused at `method_id` as `method_version_not_found`, and the message names the versions the method has. Nothing is spent: report it and ask which one to run. +`mt_…@` for a version that does not exist is refused as `pipelex.catalog.not_found` whose `params.resource` is `version`. Nothing is spent: report it in the tool's words and ask which one to run. ## A platform that does not resolve versions yet -Such a platform refuses `@draft` and `@`, and the hint says that a bare id reads the draft there. Report it in the tool's words; on that platform the bare id runs the draft. +Such a platform refuses `@draft` and `@`, and the problem's `message` says that a bare id reads the draft there. Report it in the tool's words; on that platform the bare id runs the draft. ## Which version ran diff --git a/skills/pipelex-run/references/failed-run.md b/skills/pipelex-run/references/failed-run.md index d35126b4..d5c50fb3 100644 --- a/skills/pipelex-run/references/failed-run.md +++ b/skills/pipelex-run/references/failed-run.md @@ -1,6 +1,10 @@ # A failed run -Read this at step 8 when a run failed, after giving its `failure_message` verbatim and before routing it. Route once, on what the failure says, and stop; the guards of the skill's step 8 hold throughout. +Read this at step 8 when a run failed, after giving its problem verbatim and before routing it. Route once, on what the failure says, and stop; the guards of the skill's step 8 hold throughout. + +The problem the run ended with is `run_error` on the failed state of `mthds_run_results`, `mthds_show_images` and `mthds_download_artifacts`, and `error` on `mthds_run_status`: its `code` (such as `run.timed_out`, `run.cancelled` or `model.unavailable`), its `domain` and `retry`, its `title`, `detail` and `next_step`, and its `errors`, the run's faults, of which `errors_omitted` counts those left out. The tool's summary renders it and closes with a support line, the run id, the code and the time the run ended: keep that line in the report, since it is what the people who run the platform find the run by. A run that stored no problem carries its status alone, and the summary says so. + +**Read the `domain` beside the wording.** `input` says the inputs must change and `method` that the method must; `runtime`, `account` and `operator` point away from both, at a provider, a quota, the organization's account or the platform, which is reported with its `next_step` rather than routed, unless the failure's own words match a row below. | What the failure says | Where it goes | |---|---| @@ -13,7 +17,7 @@ Read this at step 8 when a run failed, after giving its `failure_message` verbat A folder, like listed `files`, sends `.mthds` files and the templates their steps name, never a `.py` file, and a linked id fetches nothing: a caller-supplied source takes precedence over the stored method, which is read only when no folder or files were sent at all, so a linked run gains its history entry and nothing else, the stored `.py` files included. A bundle whose `PipeFunc` names a module of its own folder therefore has **no channel for its Python on any run of the directory**, linked or not. The path that carries it is `/pipelex-catalog`: a saved method run by its id alone has its `.mthds` and `.py` assembled into the run bundle server-side, the draft's as `mt_…@draft` and a version's once it is published. -So on a run of the directory the suspicion sharpens, but only when the failure says so. Where `failure_message` implicates finding or importing that function or its module, say that as the cause rather than offering it as one candidate among several, and give the cure: `/pipelex-catalog` saves the bundle with its Python as the method's draft, and `mt_…@draft`, run by its id alone, gets both. **Where it says anything else, route on what it says** — a missing input, a model or prompt fault, a failure upstream of the custom pipe — and leave the `PipeFunc` a suspect rather than promoting it: a bundle holding one is not evidence that it is what failed, and saving it with its Python cures nothing but that. +So on a run of the directory the suspicion sharpens, but only when the failure says so. Where the run's problem implicates finding or importing that function or its module, say that as the cause rather than offering it as one candidate among several, and give the cure: `/pipelex-catalog` saves the bundle with its Python as the method's draft, and `mt_…@draft`, run by its id alone, gets both. **Where it says anything else, route on what it says** — a missing input, a model or prompt fault, a failure upstream of the custom pipe — and leave the `PipeFunc` a suspect rather than promoting it: a bundle holding one is not evidence that it is what failed, and saving it with its Python cures nothing but that. ## A published address diff --git a/skills/pipelex-run/references/linked-run.md b/skills/pipelex-run/references/linked-run.md index eb68719f..35ccf212 100644 --- a/skills/pipelex-run/references/linked-run.md +++ b/skills/pipelex-run/references/linked-run.md @@ -1,7 +1,7 @@ -# A linked run refused at `method_id` +# A linked run whose id is unknown -Read this when `mthds_run` refuses a run that sent a linked directory as `method_dir` beside the `method_id` of its `pipelex-method.json` with an `input_domain` error located at `method_id`, before replying. Nothing was spent. +Read this when `mthds_run` refuses a run that sent a linked directory as `method_dir` beside the `method_id` of its `pipelex-method.json` with `pipelex.catalog.not_found`, before replying. Nothing was spent. -A linkage id the plane does not know refuses the run, and on a run that sent a folder beside the id, that location is the discriminator rather than a coincidence: a rejected payload or a refused execution locus locates at `method_dir`, or at `files` when the files were listed, so only the unknown-method arm lands at `method_id`, and its hint says the id is not visible to the API key's organization. The catalog is org-scoped, so a link made with another organization's key, or against another plane, reads exactly like a deleted method. +A linkage id the plane does not know refuses the run, and on a run that sent a folder beside the id, the problem's `code` is the discriminator rather than its wording: a rejected payload or a refused execution locus answers with a code of its own, located at `method_dir`, or at `files` when the files were listed, so only the unknown method answers `pipelex.catalog.not_found`, its `params` naming the id the API key's organization does not hold. The catalog is org-scoped, so a link made with another organization's key, or against another plane, reads exactly like a deleted method. Report it with the `api_host` the link file records — that is what makes it diagnosable — and offer the same run **without** the id: it runs the very same bundle and loses only the history filing. Do not go looking for the bundle; the bundle was never in question. diff --git a/skills/pipelex-run/references/published-address.md b/skills/pipelex-run/references/published-address.md index 61555c65..68ebef69 100644 --- a/skills/pipelex-run/references/published-address.md +++ b/skills/pipelex-run/references/published-address.md @@ -4,7 +4,7 @@ Read this at step 1 when the target is a published method's address, passed as ` ## It pairs with nothing -An address is a complete run source, so **an address pairs with nothing**: a `method_dir`, `files` or a `method_id` beside it is refused with an `input_domain` error before anything runs. Every call carries the `method_ref` alone. +An address is a complete run source, so **an address pairs with nothing**: a `method_dir`, `files` or a `method_id` beside it is refused as `client.argument_invalid` before anything runs. Every call carries the `method_ref` alone. ## It floats without a tag diff --git a/skills/pipelex-synthetic-inputs/references/photograph.md b/skills/pipelex-synthetic-inputs/references/photograph.md index 0d8d64e2..09ff5219 100644 --- a/skills/pipelex-synthetic-inputs/references/photograph.md +++ b/skills/pipelex-synthetic-inputs/references/photograph.md @@ -58,7 +58,7 @@ Its description says what changes (the side, the angle, the damage) and repeats **A room seen from two places keeps its materials and loses its walls.** The model draws what the description puts on the left and the right of the frame, but as a view straight down the room, wherever the photographer was said to stand. A second view "from the opposite corner", with the windows on its left and the fireplace on its right, therefore puts the two on facing walls, when the first photograph had them side by side. Write the room's plan before the first description, naming what is on each wall, and describe the second view by the wall it faces and what stands on the walls to its left and right: "facing the fireplace wall, the two windows on the right-hand wall, a bare wall on the left". -Follow each run with `mthds_run_status` at the hint it gives, then `mthds_run_results` once it is terminal. A failed run is reported with its `failure_message` verbatim, and that photograph is left without a path; do not retry it with a reworded description on a guess. +Follow each run with `mthds_run_status` at the hint it gives, then `mthds_run_results` once it is terminal. A failed run is reported with its problem, `run_error` (`error` on the status), verbatim, and that photograph is left without a path; do not retry it with a reworded description on a guess. ## 3. Save it diff --git a/templates/skills/pipelex-catalog/SKILL.md.j2 b/templates/skills/pipelex-catalog/SKILL.md.j2 index 7d9e6887..7b1f76a2 100644 --- a/templates/skills/pipelex-catalog/SKILL.md.j2 +++ b/templates/skills/pipelex-catalog/SKILL.md.j2 @@ -66,10 +66,10 @@ The target is a bundle directory. | a templated bundle answers `is_valid: false`, its template *not supplied with its bundle* | expected, as step 4 says: the draft runs only from its directory and cannot be published to run by id. **Never route it to editing** | | a save or a publish answers `is_valid: false` | a **produced verdict**, not an error: the save stored the draft anyway, and the publish published nothing. Report `validation_errors[]`; route a contract-preserving fix to `{{ skill_prefix }}pipelex-edit`, a structural one to `{{ skill_prefix }}pipelex-design` | | the bundle is valid with pending signatures | A **valid bundle with pending signatures is saved**, as a draft: say plainly that the method does not run yet, and which signatures are still open | -| `input_domain` at `expected_updated_at`: the draft moved since this directory synced, or it holds a pulled version | nothing was written. Read [conflict.md](references/conflict.md) before replying: unless it finds this session's own save, give the user the timestamps and the ways forward it describes. **Never choose between them.** | -| `input_domain` at `expected_draft_updated_at` | nothing was published: the draft moved since it was seen. Publish only once the user has seen it, saved or pulled, **never under the token the refusal names** | -| `input_domain` at `method_id` | read [unknown-id.md](references/unknown-id.md) before concluding anything: several faults land there. A dead link is removed only on the user's yes, the one thing this skill ever takes off disk | -| a create fails on a timeout or a transport fault | **does not retry.** A create carries no idempotency key yet, so a retry mints a second method: list the catalog first and see whether the first one landed | +| a problem at `expected_updated_at`: the draft moved since this directory synced, or it holds a pulled version | nothing was written. Read [conflict.md](references/conflict.md) before replying: unless it finds this session's own save, give the user the timestamps and the ways forward it describes. **Never choose between them.** | +| a problem at `expected_draft_updated_at` | nothing was published: the draft moved since it was seen. Publish only once the user has seen it, saved or pulled, **never under the token the refusal names** | +| `pipelex.catalog.not_found`, or a problem at `method_id` | read [unknown-id.md](references/unknown-id.md) before concluding anything: its `code` tells the faults apart. A dead link is removed only on the user's yes, the one thing this skill ever takes off disk | +| a create answers `client.outcome_unknown` | **does not retry.** A retry mints a second method: list the catalog first and see whether the first one landed | | the pull's directory holds a bundle of its own, or a link naming another method | somebody else's work: pull into another directory | | the pull's directory is linked to this method, files identical | only the link's `synced_updated_at` was refreshed: say the directory was already up to date | | linked, files differ, the saved method has **not** moved | the difference is local work this directory never saved: offer to [save](#save) it, or to pull into a new sibling directory to compare | @@ -81,4 +81,4 @@ The target is a bundle directory. - [python.md](references/python.md): the bundle holds a `PipeFunc`, before choosing `python`. - [link-file.md](references/link-file.md): a save's `link_file` came back `written: false`. - [conflict.md](references/conflict.md): a save refused at `expected_updated_at`, or a restore. -- [unknown-id.md](references/unknown-id.md): an `input_domain` error at `method_id`. +- [unknown-id.md](references/unknown-id.md): a miss, or a problem at `method_id`. diff --git a/templates/skills/pipelex-design/SKILL.md.j2 b/templates/skills/pipelex-design/SKILL.md.j2 index 0763f258..f3396190 100644 --- a/templates/skills/pipelex-design/SKILL.md.j2 +++ b/templates/skills/pipelex-design/SKILL.md.j2 @@ -61,7 +61,7 @@ Design the whole graph in memory, then write `main.mthds` in the bundle home, to Call `mthds_validate`. {% include "skills/shared/validate-call.md.j2" %} -Branch on the **structured verdict**, never on transport: `is_valid: true` is complete with `is_runnable: true` and nothing pending, and otherwise a scaffold whose backlog is the summary's `## Pending signatures`; on `is_valid: false`, fix from `validation_errors[]` and the summary's locators, then re-validate. {% include "skills/shared/validate-warnings.md.j2" %} +Branch on the **structured verdict**, never on transport: `is_valid: true` is complete with `is_runnable: true` and nothing pending, and otherwise a scaffold whose backlog is the summary's `## Pending signatures`; on `is_valid: false`, fix from `errors[]`, then re-validate. {% include "skills/shared/validate-warnings.md.j2" %} ### 6. The runnable gate and delivery @@ -86,8 +86,8 @@ For a completed method, validate once more and confirm **`is_valid: true`, `is_r | Condition | Do this | |---|---| -| `status: "error"`, class `input_domain` | fix the call | -| `status: "error"`, class `runtime` | report it, and retry once before stopping | +| `status: "error"`, `domain: "input"` | fix the call | +| any other `status: "error"` | report it, after one retry when its `retry` is `"yes"` | | validation fails twice on the same construct, or the client contract itself looks wrong | pause and show the user | ## References diff --git a/templates/skills/pipelex-edit/SKILL.md.j2 b/templates/skills/pipelex-edit/SKILL.md.j2 index 749d60bb..61e2b7cf 100644 --- a/templates/skills/pipelex-edit/SKILL.md.j2 +++ b/templates/skills/pipelex-edit/SKILL.md.j2 @@ -52,7 +52,7 @@ Check the requested change against the scope split at the top. Structural or con Validate the whole bundle **before editing**: call `mthds_validate` on the bundle directory, and branch on the structured verdict, never on transport. {% include "skills/shared/validate-call.md.j2" %} - `is_valid: true` → record whether it is runnable or a scaffold (non-empty `pending_signatures`). That same state must hold after your edits. -- `is_valid: false` → the bundle is broken **before** your change: surface the `validation_errors[]` and the Markdown summary, and offer to repair first. **Never edit on a broken baseline.** +- `is_valid: false` → the bundle is broken **before** your change: surface the `errors[]` and the Markdown summary, and offer to repair first. **Never edit on a broken baseline.** ### Step 4: Apply the edits @@ -84,8 +84,8 @@ State what changed (files and constructs), give the verdict line from the summar | Condition | Do this | |---|---| -| `status: "error"`, class `input_domain` | fix the call | -| `status: "error"`, class `runtime` | report it, and retry once before stopping | +| `status: "error"`, `domain: "input"` | fix the call | +| any other `status: "error"` | report it, after one retry when its `retry` is `"yes"` | | the same construct fails twice after your edit | pause and show the user instead of thrashing | ## References diff --git a/templates/skills/pipelex-explain/SKILL.md.j2 b/templates/skills/pipelex-explain/SKILL.md.j2 index 30406f04..89e2d39e 100644 --- a/templates/skills/pipelex-explain/SKILL.md.j2 +++ b/templates/skills/pipelex-explain/SKILL.md.j2 @@ -24,7 +24,7 @@ Read a method and say what it does, in plain language. Reading costs nothing and - **A catalog id or a published address needs the workshop**, since nothing of it is on disk. Where `mthds_get_method` is absent while the other tools answer, an id is explained at contract level, as an address is, and the explanation says which reading it is: a narrower explanation, not a stop. {% set mcp_absent_lead %}the workshop is{% endset -%} {% set mcp_absent_suffix %} That stop is only for a target that lives on the platform — a bundle directory on disk is still explained from its source, with the verdict line left out.{% endset -%} -{% set mcp_config_suffix %} Same scope: on a local bundle a `config` error costs the verdict line and nothing else — carry on and say it was not checked.{% endset -%} +{% set mcp_config_suffix %} Same scope: on a local bundle such a problem costs the verdict line and nothing else — carry on and say it was not checked.{% endset -%} {% include "skills/shared/mcp-requirements.md.j2" %} ## Guards @@ -88,11 +88,11 @@ Output: final_output | the workshop is absent, on an id or an address | stop per the Requirements: there is nothing to read | | `mthds_get_method` is absent while the other tools answer | explain the id at contract level, say the source was not read, and name the cause [not-on-disk.md](references/not-on-disk.md) gives | | an id's source comes back `truncated` | name the files you could not read and say the explanation is partial. Never describe a withheld file's pipes as absent. | -| an id is refused at `method_id` | give the tool's answer: an unknown id and an empty stored source are different answers, and an empty one is somebody's draft, not a wrong id | -| a selector call answers a no-verdict error | report the error and its `hint` verbatim; hosted address and id resolution is not live everywhere yet | +| an id is refused | give the tool's answer: an unknown id (`pipelex.catalog.not_found`) and an empty stored source (`method.package_invalid`) are different answers, and an empty one is somebody's draft, not a wrong id | +| a selector call answers a no-verdict problem | report its `detail` and `next_step` verbatim; hosted address and id resolution is not live everywhere yet | | a **local bundle** does not validate | explain it anyway from the source, say what the verdict was, and route a fix to `{{ skill_prefix }}pipelex-edit` or `{{ skill_prefix }}pipelex-design` | -| a **catalog id** does not validate | explain it from the source read above with `validation_errors[]` beside it, and say the fix is not on this disk | -| a published **address** does not validate | report `validation_errors[]` and stop: there is no source to explain, and the fix is upstream | +| a **catalog id** does not validate | explain it from the source read above with its `errors[]` beside it, and say the fix is not on this disk | +| a published **address** does not validate | report its `errors[]` and stop: there is no source to explain, and the fix is upstream | | the verdict carries no `main_pipe` | say so, and which cause the tool's message points to: the method settles no entry pipe, the contract did not come back whole, or the workshop predates the field. Do not reconstruct a signature from the input template. | {% include "skills/pipelex-explain/parts/change-route.md.j2" %} diff --git a/templates/skills/pipelex-inputs/SKILL.md.j2 b/templates/skills/pipelex-inputs/SKILL.md.j2 index 88b52097..2b4549a6 100644 --- a/templates/skills/pipelex-inputs/SKILL.md.j2 +++ b/templates/skills/pipelex-inputs/SKILL.md.j2 @@ -19,7 +19,7 @@ The one entry point for a method's inputs, through to run-ready inputs. - **`mthds_inputs_template`** is required: never hand-derive the template from the `.mthds` source. {% set mcp_config_suffix %} Never silently improvise a template.{% endset -%} {% include "skills/shared/mcp-requirements.md.j2" %} -- **`mthds_prepare_inputs`** is required at step 5, under the same two stops; never hand-fake a storage reference. +- **`mthds_prepare_inputs`** is required at step 5, under the same two stops, except `auth.forbidden` on a call with `kind` (see Stops); never hand-fake a storage reference. - **`mthds_list_methods`** and **`mthds_list_files`** are optional: without the first, ask for a saved method's `mt_…` id. ## Mode @@ -43,8 +43,8 @@ The one entry point for a method's inputs, through to run-ready inputs. The target takes three forms, one selector per call. - **A local bundle**, the usual case: `` is its directory, usually the one holding `main.mthds`, unless the caller names another. {% include "skills/shared/validate-call.md.j2" %} -- **A registered method**, an `mt_…` id with no local bundle in play, as `method_id`: bare, the latest published version; `@draft`, the draft; `@`, version n. **Say which one the template came from** (`method_version`) and offer the run on that same form; a bare id never published is refused as `method_not_published`, and `mt_…@draft` is then the target. `` is a directory the user names, by default a new `.//` without the suffix. -- **A published method**, as `method_ref: "github.com//[/][@]"`: read [references/published-address.md](references/published-address.md) before the first call. **An address with no tag is accepted, and it floats**: say so in one line, recommend the tag, and carry on. +- **A registered method**, an `mt_…` id with no local bundle in play, as `method_id`: bare, the latest published version; `@draft`, the draft; `@`, version n. **Say which one the template came from** (`method_version`) and offer the run on that same form; a bare id never published is refused as `pipelex.catalog.not_published`, and `mt_…@draft` is then the target. `` is a directory the user names, by default a new `.//` without the suffix. +- **A published method**, as `method_ref: "github.com//[/][@]"`: read [published-address.md](references/published-address.md) before the first call. **An address with no tag is accepted, and it floats**: say so in one line, recommend the tag, and carry on. ### 2. The template @@ -62,8 +62,8 @@ Evaluated in order: | No clear signal (e.g. right after `{{ skill_prefix }}pipelex-design`, with no further context) | **Template**, then offer to populate | - **Template**: replace each file-ish mock URL (an `https://` URL on a `.invalid` host) with `""`, never `""`; save, show it with its path, and offer synthetic data or the user's files. -- **Synthetic**: read [references/synthetic.md](references/synthetic.md) before generating anything. **`pipelex-synthetic-inputs` is the file factory**, and makes every file input.{% if platform == "claude" %} Invoke it with `{{ skill_prefix }}pipelex-synthetic-inputs`.{% else %} {{ harness_name }} has no cross-skill invocation, so open `../pipelex-synthetic-inputs/SKILL.md` and follow it.{% endif %} -- **User data**: read [references/user-data.md](references/user-data.md) before matching any file to an input. +- **Synthetic**: read [synthetic.md](references/synthetic.md) before generating anything. **`pipelex-synthetic-inputs` is the file factory**, and makes every file input.{% if platform == "claude" %} Invoke it with `{{ skill_prefix }}pipelex-synthetic-inputs`.{% else %} {{ harness_name }} has no cross-skill invocation, so open `../pipelex-synthetic-inputs/SKILL.md` and follow it.{% endif %} +- **User data**: read [user-data.md](references/user-data.md) before matching any file to an input. - **Mixed**: the user's files first, then synthetic values for what they leave unfilled; read both references. - **The team's files**: read [team-files.md]({{ shared_dir }}/team-files.md) before asking for a file, or for one named but not on disk. @@ -73,7 +73,7 @@ Fill the step 2 template in place, a composite native's fields included ([native ### 5. Prepare the inputs for a run -`mthds_prepare_inputs` uploads each local path, `data:` URL or inline bytes at a file input to Pipelex storage. Skip the call for the Template strategy. Otherwise, for a case's copies, **first delete any `inputs.prepared.json` an earlier prepare left in ``**, which a run would read after a prepare that writes none. Skip the call too **when every file-ish value is already an `http(s)` URL or a `pipelex-storage://` reference**: a run then reads `inputs.json`. +`mthds_prepare_inputs` uploads each local path, `data:` URL or inline bytes at a file input to Pipelex storage. Skip the call for the Template strategy. Otherwise, for a case's copies, **first delete any `inputs.prepared.json` an earlier prepare left in ``**. Skip the call too **when every file-ish value is already an `http(s)` URL or a `pipelex-storage://` reference**: a run then reads `inputs.json`. **Say what is about to leave the machine, before it does**: each file and where it goes (Pipelex storage, the user's organization, through their API key), or for a folder batch too long to list, the count and the folder; in interactive mode wait for a yes, in automatic mode state it and proceed. If the user declines, stop before the call and report that the inputs stay local and are not runnable. @@ -93,24 +93,25 @@ Say what is ready, or which placeholders are left. When a codebase here does not - no calling skill asked to stop at run-ready (a user who said not to run still gets the offer: an offer is not a run); - no placeholder remains; -- **every input the template asked for is filled** — one the factory could not make is absent, passes every other check and guarantees a failed run: say which input waits on the user, and why; +- **every input the template asked for is filled** — one the factory could not make is absent: say which input waits on the user, and why; - the inputs are run-ready: prepare succeeded, or step 5 skipped it because nothing needed uploading. -The offer names the file the run reads — `inputs.prepared.json` where prepare wrote one, else `inputs.json` — and the target: the bundle, the id or the address. +The offer names the file the run reads — `inputs.prepared.json` where prepare wrote one, else `inputs.json` — and the target. ## Stops | Condition | Do this | |---|---| -| template: `is_valid: false` | report `validation_errors[]` and the summary. A local bundle is repaired first (`{{ skill_prefix }}pipelex-design` resumes it), then retried; a registered method through `{{ skill_prefix }}pipelex-edit`, not here; a published one is reported as [its reference](references/published-address.md) says | -| template: `input_domain` | an unknown `pipe_ref` or unresolvable `main_pipe`: pass an explicit `pipe_ref`. At `method_dir`, `method_id` or `method_ref`, report it in the tool's words; another organization's id reads as a miss | -| `runtime`, either call | report, and retry once | +| template: `is_valid: false` | report `errors[]` and the summary. A local bundle is repaired first (`{{ skill_prefix }}pipelex-design` resumes it), then retried; a registered method through `{{ skill_prefix }}pipelex-edit`, not here; a published one is reported as [its reference](references/published-address.md) says | +| template: `request.pipe_not_found` or `request.pipe_ambiguous` | pass an explicit `pipe_ref`. Another `domain: "input"` problem: report it in the tool's words; another organization's id reads as a miss | +| `retry: "yes"`, either call | report, and retry once | | the factory returns no path | leave that one input unfilled, carry on with the others; report the reason and ask for the user's own file. Never fabricate a value or abandon `inputs.json` | -| prepare: `input_domain` at `inputs`, `pipe_ref`, `method_id` or `method_ref` | read [references/prepare-errors.md](references/prepare-errors.md) before replying or retrying; a storage size limit at `inputs` is terminal for this attempt | -| prepare, by address: `input_domain` at `files`, or `config` (the credential first, as the requirements say) | read [references/published-address.md](references/published-address.md) before naming a cause | +| prepare with `kind`: `auth.forbidden`, or a refusal naming `kind`, or `method_id` for `method_not_found`, `method_being_deleted` or `version_suffix` | read [synthetic.md](references/synthetic.md#test-files) before preparing again without `kind` | +| prepare: an `input` or `method` problem, not a refusal of `kind` | read [prepare-errors.md](references/prepare-errors.md) before replying or retrying; a storage size limit at `inputs` is terminal for this attempt | +| prepare, by address: refused at `files`, or an `account` problem | read [published-address.md](references/published-address.md) before naming a cause | ## References -- [synthetic.md](references/synthetic.md), [user-data.md](references/user-data.md): step 3, by strategy; both for Mixed. +- [synthetic.md](references/synthetic.md), [user-data.md](references/user-data.md): step 3, by strategy. - [published-address.md](references/published-address.md): a `method_ref` target. -- [prepare-errors.md](references/prepare-errors.md): prepare's `input_domain` errors. +- [prepare-errors.md](references/prepare-errors.md): prepare's input and method problems. diff --git a/templates/skills/pipelex-integrate/SKILL.md.j2 b/templates/skills/pipelex-integrate/SKILL.md.j2 index 29580a8e..8303c98a 100644 --- a/templates/skills/pipelex-integrate/SKILL.md.j2 +++ b/templates/skills/pipelex-integrate/SKILL.md.j2 @@ -84,7 +84,7 @@ Put the generated directory and the gate script step 10 copies in the formatter' - `status: "ok"`, `is_valid: true`, `output_dir` present → written; clean when `is_current: true` with an empty `orphans[]`. - **`orphans[]` non-empty and `drifts[]` empty** → carry on to step 7 and read [references/orphans.md](references/orphans.md). Read it off the two lists, never from `is_current`; `drifts[]` is present only when non-empty, so no `drifts` is the empty case. -- **`output_dir already holds …, which this tool does not own`** → that file is the user's: never delete, move or clear it, and never offer to; choose or ask for another directory, before the call too. +- **`client.target_exists`, a file this tool does not own** → that file is the user's: never delete, move or clear it, and never offer to; choose or ask for another directory, before the call too. - anything else (`drifts[]` included) → the stops. ### 7. The sidecar @@ -135,10 +135,10 @@ What was generated and where, the target and why, the call site's signature, the | Condition | Do this | |---|---| -| invalid, unrunnable, or `pending_signatures` | STOP, nothing generated: `validation_errors[]` to `{{ skill_prefix }}pipelex-design` or `{{ skill_prefix }}pipelex-edit`, else finish it in `{{ skill_prefix }}pipelex-design` | -| `input_domain` at `method_ref` / `method_id` | report it in the tool's words | -| `runtime` | retry once (codegen: only if `retryable: true`, same `output_dir`), then report what landed | -| `input_domain` at `output_dir`, outside the server's directory | step 1's containment: STOP, relaunch, say what is already written | +| invalid, unrunnable, or `pending_signatures` | STOP, nothing generated: `errors[]` to `{{ skill_prefix }}pipelex-design` or `{{ skill_prefix }}pipelex-edit`, else finish it in `{{ skill_prefix }}pipelex-design` | +| `domain: "input"` on `method_ref` / `method_id` | report it in the tool's words | +| `retry: "yes"`, or codegen's `client.write_failed` | retry once (codegen: same `output_dir`), then report what landed | +| `outside_workspace` at `output_dir` | step 1's containment: STOP, relaunch, say what is already written | | `is_current: false`, not step 6's orphans case | report `drifts[]` verbatim and stop; commit nothing | | no signature, by address or id | STOP as the fallback reference says; never guess the output concept | | `python-structures`, its `pipelex-sdk` after step 8 unread or below the floor, templated bundle | STOP, nothing generated: [python.md](references/python.md) | diff --git a/templates/skills/pipelex-organize/SKILL.md.j2 b/templates/skills/pipelex-organize/SKILL.md.j2 index 68c301b4..c78f539b 100644 --- a/templates/skills/pipelex-organize/SKILL.md.j2 +++ b/templates/skills/pipelex-organize/SKILL.md.j2 @@ -75,7 +75,7 @@ One short summary: the layout, one line per file saying what it holds, and the p | Condition | Do this | |---|---| | `is_valid: false` at the baseline | never reorganize a broken library: report the verdict and point to `{{ skill_prefix }}pipelex-design` to fix it first | -| `status: "error"`, class `input_domain` | fix the call | -| `status: "error"`, class `runtime` | report it, and retry once before stopping | +| `status: "error"`, `domain: "input"` | fix the call | +| any other `status: "error"` | report it, after one retry when its `retry` is `"yes"` | | the candidate still differs from the baseline after two fixes of the composition | stop, leave the original layout untouched, and report the discrepancy | | the regrouping seems to need a semantic edit (a rename, a contract fix, a missing declaration) | stop and report it: that is `{{ skill_prefix }}pipelex-design`'s work | diff --git a/templates/skills/pipelex-run/SKILL.md.j2 b/templates/skills/pipelex-run/SKILL.md.j2 index 72306f9b..c575ee24 100644 --- a/templates/skills/pipelex-run/SKILL.md.j2 +++ b/templates/skills/pipelex-run/SKILL.md.j2 @@ -89,7 +89,7 @@ When the inputs came from a lab case and the lab did not start this run, offer ` ### 8. A failed run is reported, then routed, never bisected -Give `failure_message` **verbatim** first, then read [failed-run.md](references/failed-run.md) before routing it; route once, and stop. When the method holds a `PipeFunc`, name it as a suspect: {% include 'skills/shared/pipefunc-warning.md.j2' %} Per-pipe bisection is not this skill's. Do not re-run a failed method with altered inputs to see what happens — that spends credit on a guess. +Give the run's `run_error` **verbatim** first, then read [failed-run.md](references/failed-run.md) before routing it; route once, and stop. When the method holds a `PipeFunc`, name it as a suspect: {% include 'skills/shared/pipefunc-warning.md.j2' %} Per-pipe bisection is not this skill's. Do not re-run a failed method with altered inputs to see what happens — that spends credit on a guess. ## Follow a run @@ -105,7 +105,7 @@ An unknown run id is reported in the tool's own words. | Condition | Do this | |---|---| -| `mthds_run`: `input_domain` at `method_id`, on a linked run | nothing was spent: read [linked-run.md](references/linked-run.md) before replying | +| `mthds_run`: `pipelex.catalog.not_found`, on a linked run | nothing was spent: read [linked-run.md](references/linked-run.md) before replying | | `mthds_download_artifacts` absent | say nothing was saved to disk and report the stored references as they came back; the run still completed | | `mthds_download_artifacts` refuses a `dir` the user named | take step 7's ignore check, then call again without it, which saves into `runs//`, and say so. A refused `dir` is not a failed save | @@ -113,4 +113,4 @@ An unknown run id is reported in the tool's own words. {% include 'skills/shared/reference-names.md.j2' %}- [by-id.md](references/by-id.md), [published-address.md](references/published-address.md): an `mt_…` or a `method_ref` target, before the first call. - [failed-run.md](references/failed-run.md): a failed run, before routing it. -- [linked-run.md](references/linked-run.md): a linked run refused at `method_id`. +- [linked-run.md](references/linked-run.md): a linked run whose id is unknown. diff --git a/templates/skills/shared/credentials.md.j2 b/templates/skills/shared/credentials.md.j2 index 0219b99d..4dcdaaa0 100644 --- a/templates/skills/shared/credentials.md.j2 +++ b/templates/skills/shared/credentials.md.j2 @@ -1,6 +1,6 @@ # Connecting the Pipelex workshop, and its key -Read this when an MCP-backed skill sends you here: because one of the {% if platform == "agent-skills" %}workshop's{% else %}plugin's{% endif %} `mthds_*` tools is absent from the session, or because a call returned a `config`-class error about the API key. It says what to tell the user on {{ harness_name }}, and nothing more: whether the skill stops there or carries on without the tool is the skill's own rule, which this file changes in neither direction. +Read this when an MCP-backed skill sends you here: because one of the {% if platform == "agent-skills" %}workshop's{% else %}plugin's{% endif %} `mthds_*` tools is absent from the session, or because a call returned a problem about the API key, `auth.missing_credential`, `auth.invalid_credential` or `auth.credential_expired`. It says what to tell the user on {{ harness_name }}, and nothing more: whether the skill stops there or carries on without the tool is the skill's own rule, which this file changes in neither direction. ## The tool is absent @@ -15,7 +15,9 @@ The server authenticates to the API with **`PIPELEX_API_KEY`**, which it is give {%- else -%} The server authenticates to the API with **`PIPELEX_API_KEY`**. It uses the key its host hands it, {% if platform == "mistral-vibe" %}which on {{ harness_name }} is only one written into the `env` table of its `[[mcp_servers]]` entry, since {{ harness_name }} passes a stdio MCP server only a few basic variables of your shell, such as `HOME` and `PATH`, and none of your `PIPELEX_` ones{% elif platform == "claude" %}which on {{ harness_name }} is the key entered in the **plugin configuration** when the plugin was enabled, kept in the OS keychain and exported for the server by its launcher, or else a `PIPELEX_API_KEY` exported in the shell {{ harness_name }} starts from, which Claude Desktop, launched from the desktop, never has{% else %}which on {{ harness_name }} is a `PIPELEX_API_KEY` exported in the shell {{ harness_name }} starts from, forwarded by name{% endif %}. When the host hands it none, it reads the key saved in `~/.pipelex/.env`, or in the `.env` of `PIPELEX_HOME` when that variable reaches it{% if platform == "mistral-vibe" %}, which on {{ harness_name }} also takes the entry's `env` table{% endif %}, afresh on every call, so a key saved while the session runs is used from the next call with no restart. -So a `config`-class error about the key is answered by the workshop's login, which the user runs themselves in a terminal: **`npx -y @pipelex/mcp@latest login`** opens the browser on app.pipelex.com, mints a key for the account's current organization and saves it in that file (`--paste` reads one created in the app instead, for a machine with no browser). The pipelex CLI's `pipelex login` saves to the same file, so a key it saved counts too. When the error's hint says the host's own key was refused, the saved one is never consulted until that key is removed or replaced {% if platform == "mistral-vibe" %}in the entry's `env` table{% elif platform == "claude" %}in the plugin's configuration or the shell, whichever holds it{% else %}in the shell {{ harness_name }} starts from{% endif %}. Never read that file or print a key yourself. +So a problem about the key is answered by the workshop's login, which the user runs themselves in a terminal: **`npx -y @pipelex/mcp@latest login`** opens the browser on app.pipelex.com, mints a key for the account's current organization and saves it in that file (`--paste` reads one created in the app instead, for a machine with no browser). The pipelex CLI's `pipelex login` saves to the same file, so a key it saved counts too. When the tool's summary says the host's own key was refused, the saved one is never consulted until that key is removed or replaced {% if platform == "mistral-vibe" %}in the entry's `env` table{% elif platform == "claude" %}in the plugin's configuration or the shell, whichever holds it{% else %}in the shell {{ harness_name }} starts from{% endif %}. Never read that file or print a key yourself. The plugin's validation hook reads `PIPELEX_API_KEY` from {% if platform == "claude" %}the plugin configuration or the shell{% else %}{{ harness_name }}'s environment{% endif %} alone, never from that file, so with only a saved key it still lints and formats each edit but skips validating it against the API{% if platform == "mistral-vibe" %}: exporting `PIPELEX_API_KEY` in the shell {{ harness_name }} starts from restores that stage{% endif %}. {%- endif %} + +`auth.forbidden` is not about the key: the platform refused the action for the role the key's owner holds in the organization, and its `detail` names that role and what the action needs. No login or new key changes a role, so relay it as it came and never send the user to the login for it. diff --git a/templates/skills/shared/mcp-requirements.md.j2 b/templates/skills/shared/mcp-requirements.md.j2 index b1e47143..362cc0a0 100644 --- a/templates/skills/shared/mcp-requirements.md.j2 +++ b/templates/skills/shared/mcp-requirements.md.j2 @@ -1,26 +1,27 @@ {#- The Pipelex MCP requirements, shared by every MCP-backed skill: its two stops. Box F of the size diet's design (L-260923-a9bdfe) shrank this block to the stops a - model must have read before it acts — an absent tool, a `config`-class error - surfaced verbatim — and moved what to tell the user about connecting the - workshop and where its key comes from into `shared/credentials.md`, a - reference rendered per target and read when one of those stops fires. The - stop stays here; only its recovery moved. + model must have read before it acts — an absent tool, and a problem in the + `account` domain (a missing or refused key, a role, the organization's credit) + or an unreachable API, its next step relayed verbatim — and moved what to tell + the user about connecting the workshop and where its key comes from into + `shared/credentials.md`, a reference rendered per target and read when one of + those stops fires. The stop stays here; only its recovery moved. The including template sets what it changes with `{% set %}` before the include; anything it leaves alone falls back to the common wording: mcp_absent_lead — "the tool is" (default), "the tools are", "a tool is" mcp_absent_suffix — a sentence appended to the absent-tool bullet - mcp_config_parenthetical — the aside between the `config` class and the comma - mcp_config_suffix — a sentence appended to the config-error bullet - mcp_requirements_extra — a bullet rendered after the config-error bullet, + mcp_config_parenthetical — the aside between the problem it names and the comma + mcp_config_suffix — a sentence appended to the account-problem bullet + mcp_requirements_extra — a bullet rendered after the account-problem bullet, for a skill whose own tool note sits there The fragment strips its own trailing newline (the closing comment below), so it can be included inline as well as on a line of its own. -#} - **If {{ mcp_absent_lead | default("the tool is") }} absent from this session**, the Pipelex MCP server isn't connected: STOP, and tell the user in one line what [the connection reference]({{ shared_dir }}/credentials.md#the-tool-is-absent) says for {{ harness_name }}.{{ mcp_absent_suffix | default("") }} -- **If a call returns `status: "error"` with an error of class `config`**{{ mcp_config_parenthetical | default(" (missing or rejected `PIPELEX_API_KEY`, unreachable API)") }}, STOP the same way and surface the error's `hint` verbatim; when it is about the key, read [where the key comes from]({{ shared_dir }}/credentials.md#where-the-key-comes-from) before saying anything more.{{ mcp_config_suffix | default("") }} +- **If a call returns a problem in the `account` domain, or `client.unreachable`**{{ mcp_config_parenthetical | default(" (missing or rejected `PIPELEX_API_KEY`, unreachable API)") }}, STOP the same way and relay its `next_step` verbatim; when it is about the key, read [where the key comes from]({{ shared_dir }}/credentials.md#where-the-key-comes-from) before saying anything more.{{ mcp_config_suffix | default("") }} {%- if mcp_requirements_extra is defined %} {{ mcp_requirements_extra }} {%- endif %} diff --git a/templates/skills/shared/saved-copy-notice.md.j2 b/templates/skills/shared/saved-copy-notice.md.j2 index ac53cd7c..ce01642b 100644 --- a/templates/skills/shared/saved-copy-notice.md.j2 +++ b/templates/skills/shared/saved-copy-notice.md.j2 @@ -28,5 +28,5 @@ Strips its own trailing newline (the closing comment below), so it can be included inline as well as on a line of its own. -#} -**Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. {% include "skills/shared/template-not-stored.md.j2" %} **Never publish here: a publish is `{{ skill_prefix }}pipelex-catalog`'s, on the user's request.** Leave the save to `{{ skill_prefix }}pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a `config`-class error included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. +**Save the linked method's draft.** A `pipelex-method.json` beside the root `.mthds` file links this directory to a saved method, which lacks this change. Once this skill's own final verdict has proven the change, call `mthds_save_method` with the validated `.mthds` files as `{ path }`, root first, and the link's `method_id`, and nothing else: **no `name`, no `expected_updated_at`, no `python`, no `link_dir`**, and no template file — the workshop sends the link's token itself. Report it by name and id, with what the tool says `mt_…@draft` and the bare id now run, and its words on a link it could not write. {% include "skills/shared/template-not-stored.md.j2" %} **Never publish here: a publish is `{{ skill_prefix }}pipelex-catalog`'s, on the user's request.** Leave the save to `{{ skill_prefix }}pipelex-catalog`, saying the change is not saved, when the tool is absent or refuses, a problem in the `account` domain included, when the workshop will not read the path, or when this work changed a `PipeFunc`'s Python; never retry with a token or inline. No link file means there is nothing to save to. Never write or edit `pipelex-method.json`: it is the workshop's. {#- -#} diff --git a/templates/skills/shared/validate-warnings.md.j2 b/templates/skills/shared/validate-warnings.md.j2 index a3f65525..ec837f81 100644 --- a/templates/skills/shared/validate-warnings.md.j2 +++ b/templates/skills/shared/validate-warnings.md.j2 @@ -1,8 +1,8 @@ {#- What a skill does with the advisory `warnings` a valid `mthds_validate` - verdict carries (`pipelex-mcp`, SPEC.md, the validate output): they never - change `is_valid`, so the skill reports them, and a `template_check_warning`, - a `PipeDocGen` step's template check finding something in the template file - it was sent, is acted on as the MTHDS reference's "Template files" says, + verdict carries (`pipelex-mcp`, SPEC.md, the validate output), one problem + item each: they never change `is_valid`, so the skill reports them, and a + `pipelex.docgen.template_warning`, a `PipeDocGen` step's template check + finding something in the template file it was sent, is acted on as the MTHDS reference's "Template files" says, which tells a skill that writes the method from one that only reads or runs it. Included where a skill reads a validation verdict it reports: design's validation, edit's re-validation, explain's verdict line and run's proof @@ -12,5 +12,5 @@ Strips its own trailing newline (the closing comment below), so it can be included mid-paragraph. -#} -**Report a valid verdict's `warnings`**, and read [template files]({{ shared_dir }}/writing-mthds.md#template-files) before acting on a `template_check_warning`. +**Report a valid verdict's `warnings`**, and read [template files]({{ shared_dir }}/writing-mthds.md#template-files) before acting on a `pipelex.docgen.template_warning`. {#- -#} diff --git a/templates/skills/shared/writing-mthds.md.j2 b/templates/skills/shared/writing-mthds.md.j2 index 1c851a49..a39e15d5 100644 --- a/templates/skills/shared/writing-mthds.md.j2 +++ b/templates/skills/shared/writing-mthds.md.j2 @@ -714,7 +714,7 @@ A dry run composes the document for real against mock inputs, which checks the t **The catalog stores no template file yet**: `mthds_save_method` takes `.mthds` and `.py` files alone, so a saved method whose step names a template file does not load by its id, while its directory still validates and runs as `method_dir`. -**A `template_check_warning` in a valid verdict's `warnings`** is the template check's finding in the file a step names, located by its `pipe_code`, `template_file` and `template_location`, such as a field that matches no input of the step. It never changes `is_valid`, but the printed file may show it. A skill that writes the method fixes it in the template it wrote, or in the step, and validates again; a template the user supplied is theirs, so name the finding and ask before changing it. A skill that only reads or runs the method reports it with the verdict. +**A `pipelex.docgen.template_warning` in a valid verdict's `warnings`** is the template check's finding in the file a step names, a problem item located at the step's pipe (`location.pipe`) whose `params` carry `template_file`, the file as the step names it, and `template_location`, where in the file, such as a field that matches no input of the step. It never changes `is_valid`, but the printed file may show it. A skill that writes the method fixes it in the template it wrote, or in the step, and validates again; a template the user supplied is theirs, so name the finding and ask before changing it. A skill that only reads or runs the method reports it with the verdict. ### PipeFunc — call a Python function of the method's folder diff --git a/tests/unit/test_gen_skill_docs.py b/tests/unit/test_gen_skill_docs.py index 83f58237..32014e63 100644 --- a/tests/unit/test_gen_skill_docs.py +++ b/tests/unit/test_gen_skill_docs.py @@ -978,8 +978,8 @@ def test_absent_tools_stop_message_matches_platform(self, target_name: str, mani def test_credential_sentence_names_the_platform_channel(self, target_name: str) -> None: """Where the workshop gets its API key from differs per harness, so the sentence differs per harness — it used to be shared by Claude and Codex. - It lives in `shared/credentials.md`, read when a `config` error is about - the key, and no skill restates it. + It lives in `shared/credentials.md`, read when a problem in the `account` + domain is about the key, and no skill restates it. On every harness the workshop takes the host's key first and the key its login saved in `~/.pipelex/.env` otherwise, so the login is the answer to @@ -1304,7 +1304,7 @@ def test_a_folder_form_skill_names_files_only_where_the_folder_cannot_go(self, t everywhere = "Inline `files` (" exceptions = { "pipelex-explain": "**A single file goes as `files` instead**", - "pipelex-inputs": "`input_domain` at `files`", + "pipelex-inputs": "refused at `files`", } repo_root = self.REPO_TEMPLATES.parent config = load_target_config(repo_root / "targets", target_name) @@ -1347,14 +1347,14 @@ def test_a_valid_verdicts_warnings_are_read_where_a_skill_reports_the_verdict(se among them. The skills that report a verdict read them: design and edit, which fix what they wrote, explain's verdict line and run's proof before spending credit. Integrate's validation is a gate it reports nothing of, and the save, the inputs template and organize's proof carry no such verdict, so the - roster is pinned here, with the pointer to where a `template_check_warning` is read.""" + roster is pinned here, with the pointer to where a `pipelex.docgen.template_warning` is read.""" include = "skills/shared/validate-warnings.md.j2" carriers = sorted( path.parent.name for path in (self.REPO_TEMPLATES / "skills").glob("*/SKILL.md.j2") if include in _skill_source(path.parent) ) assert carriers == ["pipelex-design", "pipelex-edit", "pipelex-explain", "pipelex-run"] partial = (self.REPO_TEMPLATES / "skills" / "shared" / include.rsplit("/", 1)[1]).read_text(encoding="utf-8") - assert "({{ shared_dir }}/writing-mthds.md#template-files) before acting on a `template_check_warning`" in partial + assert "({{ shared_dir }}/writing-mthds.md#template-files) before acting on a `pipelex.docgen.template_warning`" in partial @pytest.mark.parametrize("skill", MCP_SKILLS) def test_mcp_backed_skill_includes_the_requirements_block(self, skill: str) -> None: @@ -1615,7 +1615,7 @@ def test_it_routes_a_failure_and_never_bisects(self) -> None: assert "never bisected" in body or "never bisects" in body assert "Per-pipe bisection is not this skill's" in body assert "Do not re-run a failed method with altered inputs" in body - assert "`failure_message` **verbatim**" in body + assert "`run_error` **verbatim**" in body def test_a_stuck_run_is_named_rather_than_waited_on(self) -> None: """A durable run sitting in RUNNING with no error may be a workflow task that @@ -1916,14 +1916,17 @@ def test_the_python_rule_reads_function_name_as_an_import_path(self) -> None: assert "flat, process-wide function registry" not in text, "the registry reading is retired and must not come back" assert "never an import path" not in text, "the registry reading is retired and must not come back" - def test_an_input_domain_error_at_method_id_is_not_read_as_an_unknown_id(self) -> None: - """A rejected payload, an organization-context failure and the workshop's own - refusal when the link names another method all land at `method_id`. Reading - the location alone removes a good `pipelex-method.json` and mints a duplicate - nothing in this plugin can delete.""" + def test_a_problem_at_method_id_is_not_read_as_an_unknown_id(self) -> None: + """A rejected payload, an organization-context failure, a version suffix and the + workshop's own refusal when the link names another method all land on the same + id. Reading the location alone removes a good `pipelex-method.json` and mints a + duplicate nothing in this plugin can delete, so the reference reads the code.""" unknown_id = self.catalog_reference("unknown-id.md") - assert "The location alone never tells them apart**" in unknown_id - assert "only the not-found answer names `pipelex-method.json` and the `api_host`" in unknown_id + assert "**the problem's `code` tells them apart**, never its location or its wording" in unknown_id + assert "Only `pipelex.catalog.not_found` whose `params.resource` is `method` is a miss" in unknown_id + assert "`client.target_exists` at `method_id`" in unknown_id + assert "**A version suffix is refused there, as `version_suffix`, and is not a miss.**" in unknown_id + assert "report the miss **with the `api_host` the link file records**" in unknown_id assert "read [unknown-id.md](references/unknown-id.md) before concluding anything" in self.catalog_skill def test_the_landing_path_is_stated_relative_to_the_workshop(self) -> None: @@ -2178,14 +2181,14 @@ class TestPipelexInputsSizeLimitDiscipline: derived file uploaded in place of the user's is silently wrong — so it stays in `SKILL.md`, once, at the prepare step. The failure branches announce themselves by the error, so they moved to `references/prepare-errors.md`, which the stop - table points at, keyed on the error's `location`. + table points at, keyed on the problem's `code`. """ REPO_ROOT = Path(__file__).parents[2] TEMPLATE = REPO_ROOT / "templates" / "skills" / "pipelex-inputs" / "SKILL.md.j2" REFERENCE = REPO_ROOT / "skills" / "pipelex-inputs" / "references" / "prepare-errors.md" - SIZE_BRANCH = '## `location: "inputs"` and the response reports a storage size limit' - NON_SIZE_BRANCH = '## `location: "inputs"` and the response is not a size-limit failure' + SIZE_BRANCH = "## `upload_too_large`: a file over the storage size limit" + NON_SIZE_BRANCH = "## A file the walk could not read or take" GUARDRAILS = ( "A preflight size check may inform the report, but it is never a reason to transform, derive, or substitute the asset", "Do not compress, optimize, re-encode, resize, downsample, split, truncate, extract pages or content, or convert it", @@ -2209,7 +2212,8 @@ def test_size_limit_is_terminal_without_asset_or_input_mutation(self) -> None: size_branch = self.reference.split(self.SIZE_BRANCH, maxsplit=1)[1].split(self.NON_SIZE_BRANCH, maxsplit=1)[0] assert "This is a terminal branch for the current preparation attempt." in size_branch - assert "quote the tool's exact `message` and `hint` verbatim" in size_branch + assert "`client.argument_invalid` at `inputs` whose `params.reason` is `upload_too_large`" in size_branch + assert "quote the tool's exact `message` and `next_step` verbatim" in size_branch assert "actual file size and the allowed limit whenever the response provides them" in size_branch assert "preparation failed, the inputs are not run-ready, and no run will be offered" in size_branch assert "preserve the user's original file" in size_branch @@ -2244,7 +2248,7 @@ def test_every_platform_renders_the_same_size_limit_guardrails(self, target_name for guardrail in self.GUARDRAILS: assert guardrail in body, f"{target_name}: missing oversized-asset guardrail: {guardrail}" # The stop table sends the model to the branch, and says the size limit is terminal on its own line. - stop_row = next(line for line in body.splitlines() if line.startswith("| prepare: `input_domain` at `inputs`")) + stop_row = next(line for line in body.splitlines() if line.startswith("| prepare: an `input` or `method` problem")) assert "](references/prepare-errors.md)" in stop_row assert "a storage size limit at `inputs` is terminal for this attempt" in stop_row shipped = resolve_output_dir(self.REPO_ROOT, config.source) / "skills" / "pipelex-inputs" / "references" / "prepare-errors.md" @@ -2788,7 +2792,7 @@ def test_an_absent_main_pipe_is_named_and_never_reconstructed(self) -> None: def test_an_invalid_remote_method_is_reported_and_not_routed_to_disk(self) -> None: """Round 1, Codex: an invalid id or address projects no `main_pipe` and - answers `validation_errors[]` instead of shapes, so there is nothing to + answers `errors[]` instead of shapes, so there is nothing to explain — and `/pipelex-edit` cannot reach a method that is not on disk. The routing is the not-on-disk reference's since the size diet; the stop rows stay in the skill.""" @@ -3201,7 +3205,7 @@ def test_an_address_pairs_with_no_other_selector(self) -> None: # A second selector is a refusal, not a normalization the skill performs silently # on the user's behalf. assert "drops the extra one" not in body + reference - assert "refused with an `input_domain` error before anything runs" in reference + assert "refused as `client.argument_invalid` before anything runs" in reference # And the skill does not resolve the ambiguity itself: a run is paid, so two # targets in hand is a question for the user, not a selector to quietly omit. # The stop row that restated it went in the size diet; the guard at step 1 holds it. @@ -3239,7 +3243,7 @@ def test_the_stale_workshop_refusal_is_read_off_the_error_it_produces(self) -> N was supplied, NOT at `method_ref`. An agent told to look for the latter reads a stale workshop as a missing bundle and goes hunting for files that do not exist. The reading is the address reference's, and the stop table keys on the error.""" - assert "`input_domain` at `files`" in self.inputs_skill + assert "refused at `files`" in self.inputs_skill body = self.inputs_address_reference assert "Provide MTHDS files or a method_id" in body assert "npx -y @pipelex/mcp@latest" in body @@ -3249,21 +3253,24 @@ def test_the_stale_workshop_refusal_is_read_off_the_error_it_produces(self) -> N assert "restarts the server" in body assert "leaving them refreshing in a loop" in body - def test_the_address_config_refusal_names_the_gate_without_suppressing_the_credential(self) -> None: - """Prepare resolves an address through the run route, so a published package - shipping in-process Python is refused there — in the same `config` arm, wearing - the deployment's authentication wording. Naming that cause is worth doing; the - first draft went further and told the agent the credential was fine, which the - round refuted: preparation uploads with the key and templating never exercises - that, so a template call that succeeded rules nothing out, and the arm also - covers a paywall, an unreachable API and a missing upload route. The credential - stays the first thing checked, because it is the one the user can act on.""" - assert "`config` (the credential first, as the requirements say)" in self.inputs_skill + def test_an_address_account_problem_on_prepare_is_the_credential_alone(self) -> None: + """Prepare once read an address's signature through the run route, so a published + package shipping in-process Python was refused there, wearing the credential's + wording, and the reference named that second cause (L-260923-4ce273). Prepare now + reads `POST /v1/pipe-io`, which loads the package's `.mthds` files alone, so the + execution-locus gate never fires on it: a problem in the `account` domain is the + credential and only the credential, and the deployment's refusal of Python meets + the run. A template call that succeeded still rules nothing out, since preparation + uploads with the key and templating never exercises that.""" + address_row = next(line for line in self.inputs_skill.splitlines() if line.startswith("| prepare, by address:")) + assert "an `account` problem" in address_row body = self.inputs_address_reference - assert "in-process Python" in body - assert "the credential first" in body + assert "## Prepare, a problem in the `account` domain: the credential, and only the credential" in body + assert "deal with the credential first" in body assert "rules nothing out" in body - assert "the key is not what failed" not in body + assert "never reaches it" in body + assert "`pipelex.deployment.custom_code_requires_sandbox`, meets the run instead" in body + assert "wearing the deployment's authentication wording" not in body class TestCatalogIdInEverySkill: @@ -3407,9 +3414,9 @@ def test_the_notice_never_forces_a_save_over_a_newer_draft(self) -> None: # A link the save could not refresh makes the next save from the directory a refusal that a later # session reads as somebody else's save, so the notice relays the tool's words on it. assert "and its words on a link it could not write" in body - # A key that may validate but not write the catalog makes the save a `config`-class error; that is - # this save's failure alone, never a reason to stop over a change already validated on disk. - assert "when the tool is absent or refuses, a `config`-class error included" in body + # A key that may validate but not write the catalog makes the save a problem in the `account` domain; that + # is this save's failure alone, never a reason to stop over a change already validated on disk. + assert "when the tool is absent or refuses, a problem in the `account` domain included" in body assert "Leave the save to `{{ skill_prefix }}pipelex-catalog`, saying the change is not saved" in body bridge = (self.TEMPLATES / "shared" / "catalog-id-bridge.md.j2").read_text(encoding="utf-8") assert "`{{ skill_prefix }}pipelex-catalog` is what compares the two" in bridge @@ -3447,14 +3454,14 @@ def test_a_linked_run_does_not_read_as_the_saved_method_having_run(self) -> None assert "do not let the filing read as the saved method having run" in body def test_a_files_run_blames_the_pipefunc_only_when_the_failure_does(self) -> None: - """Step 8's standing rule is to route once from `failure_message`. + """Step 8's standing rule is to route once from the run's problem, `run_error`. Holding a `PipeFunc` is not evidence that one failed: a run that dies on a missing input upstream of the custom pipe would otherwise be declared a failure to find its function and sent to `/pipelex-catalog`, which is a deployment gesture and no cure for a missing input. The reading is the failure reference's since the size diet, and step 8 points at it before routing.""" body = self.run_reference("failed-run.md") - assert "Where `failure_message` implicates finding or importing that function or its module" in body + assert "Where the run's problem implicates finding or importing that function or its module" in body assert "**Where it says anything else, route on what it says**" in body assert "not evidence that it is what failed" in body assert "then read [failed-run.md](references/failed-run.md) before routing it" in self.skill("pipelex-run") @@ -3472,20 +3479,18 @@ def test_a_linked_run_carries_no_stored_python(self) -> None: assert "never a `.py` file" in body assert "assembled into the run bundle server-side" in body - def test_an_unknown_linkage_id_is_read_off_a_location_that_discriminates(self) -> None: - """`RUN_START_MIXED_ERROR_OPTIONS` splits the locations deliberately: a - rejected payload and a refused execution locus land at `files`, which the - workshop relocates to `method_dir` for a folder, and only the unknown-method - arm lands at `method_id`. That is the opposite of - `/pipelex-catalog`'s save, where one location carries several causes — - so the reason is stated, and an agent does not carry either rule to the - other place. The reading is `linked-run.md`'s, which the stop table's row - for that refusal points at.""" + def test_an_unknown_linkage_id_is_read_off_its_code(self) -> None: + """A rejected payload and a refused execution locus on a linked run answer + with codes of their own, located at `method_dir` or `files`, and only the + unknown method answers `pipelex.catalog.not_found`, which names the id. The + code is the discriminator, as it is in `/pipelex-catalog`'s save, where one + location carries several causes. The reading is `linked-run.md`'s, which the + stop table's row for that refusal points at.""" body = self.run_reference("linked-run.md") - assert "that location is the discriminator rather than a coincidence" in body + assert "the problem's `code` is the discriminator rather than its wording" in body assert "api_host` the link file records" in body assert "without** the id" in body - assert "| `mthds_run`: `input_domain` at `method_id`, on a linked run |" in self.skill("pipelex-run") + assert "| `mthds_run`: `pipelex.catalog.not_found`, on a linked run |" in self.skill("pipelex-run") def test_explain_reads_a_saved_method_and_writes_none_of_it(self) -> None: """Box F.4 amended. `mthds_get_method`'s other arm writes the sources @@ -3514,7 +3519,7 @@ def test_explain_says_a_bounded_read_is_partial(self) -> None: assert "Never describe a withheld file's pipes as absent." in body def test_explain_keeps_an_empty_stored_source_distinct_from_an_unknown_id(self) -> None: - """Both are `input_domain` at `method_id`; one is somebody's draft and + """`method.package_invalid` and `pipelex.catalog.not_found`; one is somebody's draft and the other is a wrong id, and collapsing them sends the user hunting for a typo in an id that is correct.""" body = self.skill("pipelex-explain") diff --git a/tests/unit/test_language_reference.py b/tests/unit/test_language_reference.py index cee85ca6..350600c3 100644 --- a/tests/unit/test_language_reference.py +++ b/tests/unit/test_language_reference.py @@ -223,12 +223,13 @@ def test_a_template_is_written_before_the_step_that_names_it(self, target_name: def test_the_catalog_and_the_template_check_are_said_where_template_files_are(self) -> None: """`mthds_save_method` takes `.mthds` and `.py` files alone, so a saved method whose step names a template - file does not load by its id; and a valid verdict's `template_check_warning` is acted on by whoever wrote + file does not load by its id; and a valid verdict's `pipelex.docgen.template_warning` is acted on by whoever wrote the template, which the skills that report a verdict point at.""" docgen = section(rendered_shared("prod", "writing-mthds.md"), "### PipeDocGen — ") assert "**The catalog stores no template file yet**" in docgen assert "does not load by its id, while its directory still validates and runs as `method_dir`" in docgen - assert "**A `template_check_warning` in a valid verdict's `warnings`**" in docgen + assert "**A `pipelex.docgen.template_warning` in a valid verdict's `warnings`**" in docgen + assert "located at the step's pipe (`location.pipe`) whose `params` carry `template_file`" in docgen assert "It never changes `is_valid`, but the printed file may show it." in docgen assert "a template the user supplied is theirs, so name the finding and ask before changing it" in docgen diff --git a/tests/unit/test_pipelex_catalog_skill.py b/tests/unit/test_pipelex_catalog_skill.py index 56b124b9..3fc0fa05 100644 --- a/tests/unit/test_pipelex_catalog_skill.py +++ b/tests/unit/test_pipelex_catalog_skill.py @@ -57,8 +57,8 @@ def test_each_branch_is_pointed_at_where_it_is_taken(self, target_name: str) -> body = self.render(target_name) at_the_decision = { "3. **Decide `python`.**": "references/python.md", - "| `input_domain` at `expected_updated_at`": "references/conflict.md", - "| `input_domain` at `method_id`": "references/unknown-id.md", + "| a problem at `expected_updated_at`": "references/conflict.md", + "| `pipelex.catalog.not_found`, or a problem at `method_id`": "references/unknown-id.md", "on `written: false`, read [link-file.md]": "references/link-file.md", "When the workshop refuses a path, read [link-file.md]": "references/link-file.md", } @@ -76,7 +76,10 @@ def test_the_unknown_id_reference_answers_a_pull_too(self) -> None: reference = self.reference("unknown-id.md") assert "`mthds_save_method`, `mthds_publish_method` or a pull's `mthds_get_method`" in reference.splitlines()[2] assert "**A pull or a publish has no link to judge.**" in reference - assert "An empty stored source answers at the same location and is not a miss" in reference + assert ( + "`method.package_invalid` with `params.reason` `empty_tree` is a pull of a method whose stored source holds no file yet. It is not a miss" + in reference + ) @pytest.mark.parametrize("target_name", TARGETS) def test_each_branch_keeps_its_guard_at_the_pointer(self, target_name: str) -> None: @@ -85,8 +88,8 @@ def test_each_branch_keeps_its_guard_at_the_pointer(self, target_name: str) -> N ways are the user's to choose between, and a dead link is removed only on a yes.""" body = self.render(target_name) assert "do not sweep the directory" in self.the_line(body, "3. **Decide `python`.**") - assert "**Never choose between them.**" in self.the_line(body, "| `input_domain` at `expected_updated_at`") - assert "removed only on the user's yes" in self.the_line(body, "| `input_domain` at `method_id`") + assert "**Never choose between them.**" in self.the_line(body, "| a problem at `expected_updated_at`") + assert "removed only on the user's yes" in self.the_line(body, "| `pipelex.catalog.not_found`, or a problem at `method_id`") @pytest.mark.parametrize("target_name", TARGETS) def test_the_pull_refusals_are_stated_once_in_the_stop_table(self, target_name: str) -> None: diff --git a/tests/unit/test_pipelex_explain_skill.py b/tests/unit/test_pipelex_explain_skill.py index 2937907f..9d08b6e4 100644 --- a/tests/unit/test_pipelex_explain_skill.py +++ b/tests/unit/test_pipelex_explain_skill.py @@ -74,7 +74,7 @@ def test_the_workshop_stays_optional(self, target_name: str) -> None: assert "Never refuse to explain a local bundle because the workshop is not connected." in requirements assert "a narrower explanation, not a stop" in requirements assert "That stop is only for a target that lives on the platform" in requirements - assert "Same scope: on a local bundle a `config` error costs the verdict line and nothing else" in requirements + assert "Same scope: on a local bundle such a problem costs the verdict line and nothing else" in requirements def test_the_reference_is_static_and_says_when_it_is_read(self) -> None: """References are copied verbatim into every target and never rendered, so a template expression in one diff --git a/tests/unit/test_pipelex_inputs_skill.py b/tests/unit/test_pipelex_inputs_skill.py index 19073c55..5aa2ad20 100644 --- a/tests/unit/test_pipelex_inputs_skill.py +++ b/tests/unit/test_pipelex_inputs_skill.py @@ -74,7 +74,8 @@ def test_each_branch_is_pointed_at_where_it_is_taken(self, target_name: str) -> "- **Synthetic**: read [": ("references/synthetic.md",), "- **User data**: read [": ("references/user-data.md",), "| template: `is_valid: false` |": ("references/published-address.md",), - "| prepare: `input_domain` at `inputs`": ("references/prepare-errors.md",), + "| prepare with `kind`:": ("references/synthetic.md#test-files",), + "| prepare: an `input` or `method` problem": ("references/prepare-errors.md",), "| prepare, by address:": ("references/published-address.md",), "- **The team's files**: read [": ("../shared/team-files.md",), "The factory's files take `kind`": ("references/synthetic.md#test-files",), @@ -191,7 +192,11 @@ def test_the_factory_s_files_go_up_as_the_method_s_test_files(self) -> None: assert "`.pipelex/method.json`" in section assert "Prepare in two calls" in section assert "Write the second call's `inputs` as step 5 says, and nothing when either call fails." in section - assert 'as `input_domain` at `kind`, or as a `config` error tagged `kind: "role"`' in section + assert ( + "as `client.argument_invalid` at `kind` or at `method_id` with `params.reason` `method_not_found`, " + "`method_being_deleted` or `version_suffix`, or as `auth.forbidden`" + ) in section + assert "such as `not_a_catalog_id`, is a fault of the target that dropping `kind` does not cure" in section assert "Prepare again without `kind`" in section assert "never yours" in section assert "echoes no `kind`" in section diff --git a/tests/unit/test_pipelex_integrate_skill.py b/tests/unit/test_pipelex_integrate_skill.py index 7f57d1bf..433267c6 100644 --- a/tests/unit/test_pipelex_integrate_skill.py +++ b/tests/unit/test_pipelex_integrate_skill.py @@ -373,11 +373,14 @@ def test_the_helper_budget_is_one_and_does_not_license_a_second(self) -> None: def test_failure_posture_pins_the_403_and_the_orphans(self) -> None: body = self.integrate assert "A **403** on `mthds_codegen` is a feature gate, not a key problem" in body - # The plan limit is a `config` error like any other, so the shared stop surfaces its hint verbatim. - assert "surface the error's `hint` verbatim" in self.render("prod") + # The plan limit is a problem in the `account` domain like any other, so the shared stop relays its next step verbatim. + assert ( + "If a call returns a problem in the `account` domain, or `client.unreachable`**, STOP the same way and relay its `next_step` verbatim" + in self.render("prod") + ) assert "**Never delete an orphan, and never offer to clean orphans up**" in body assert "the orphan paths, by name, and that none of them were deleted" in self.reference("orphans.md") - assert "never delete, move or clear it, and never offer to" in self.the_line(body, "which this tool does not own") + assert "never delete, move or clear it, and never offer to" in self.the_line(body, "a file this tool does not own") # A lock is not this method's without a sidecar naming it: same file names mean a silent overwrite, not an orphan. assert "is this method's only when a `sources.json` beside it names this method" in body assert "so another method's files would be silently overwritten, not orphaned" in body diff --git a/tests/unit/test_pipelex_run_skill.py b/tests/unit/test_pipelex_run_skill.py index 379091c8..305a15ec 100644 --- a/tests/unit/test_pipelex_run_skill.py +++ b/tests/unit/test_pipelex_run_skill.py @@ -67,8 +67,8 @@ def test_each_branch_is_pointed_at_where_it_is_taken(self, target_name: str) -> at_the_decision = { "as `method_ref`: read [": ("references/by-id.md", "references/published-address.md"), "an address's verdict is reported as [": ("references/published-address.md",), - "Give `failure_message` **verbatim** first": ("references/failed-run.md",), - "| `mthds_run`: `input_domain` at `method_id`": ("references/linked-run.md",), + "Give the run's `run_error` **verbatim** first": ("references/failed-run.md",), + "| `mthds_run`: `pipelex.catalog.not_found`": ("references/linked-run.md",), "1. **Values the user gave in the request**": ("../shared/team-files.md",), } for decision, targets in at_the_decision.items(): diff --git a/tests/unit/test_skill_error_fields.py b/tests/unit/test_skill_error_fields.py index 305077e4..5a1f11ed 100644 --- a/tests/unit/test_skill_error_fields.py +++ b/tests/unit/test_skill_error_fields.py @@ -1,17 +1,22 @@ -"""No shipped skill teaches a field of the error report the MTHDS problem document replaced. - -The runtime's error report carried a class name as `error_type`, who must act as `error_domain` and `error_category`, -the next step as `user_action`, and whether its message was meant for the caller as `caller_facing_message`. The -problem document replaces them with `code`, `domain`, `retry`, `next_step`, `location` and its items in `errors`, and -pipelex writes none of them from the release that brings it. The workshop, the Pipelex MCP server the skills read -errors through, still relays them on a failed run's `failure` object while the hosted plane runs an older pipelex, -and drops them when it moves to the problem document, so a skill that came to depend on one would break then. - -The workshop's own error contract is not on this list, since it is what the skills read today: a no-verdict -`status: "error"` with `errors[]` entries carrying a `class`, `retryable`, `location`, `hint` and `kind`, an invalid -verdict's `validation_errors[]`, and a failed run's `failure_message` (pipelex-mcp's `SPEC.md`, "Verdicts and -errors"). That contract moves to the problem document with the workshop itself, when the hosted plane and its clients -do (L-261015-4286ad), and the skills that name it move in the same change. +"""No shipped skill teaches an error field nobody sends any more. + +Two error vocabularies are retired, both by the MTHDS problem document. The runtime's error report carried a class name +as `error_type`, who must act as `error_domain` and `error_category`, the next step as `user_action`, and whether its +message was meant for the caller as `caller_facing_message`; pipelex writes none of them from the release that brings the +problem document. The workshop, the Pipelex MCP server the skills read errors through, had a contract of its own: a +no-verdict `status: "error"` whose `errors[]` entries carried a `class` (`input_domain`, `config`, `runtime`), a +`retryable` flag, a free-string `location`, a `hint` and a `kind` tag (`kind: "auth"`, `kind: "role"`), an invalid +verdict's `validation_errors[]`, a failed run's `failure` object and `failure_message`, a template check's +`template_check_warning`, and the platform's old codes `method_not_published` and `method_version_not_found`. + +The workshop now answers a no-verdict call with one `problem`, the caller's view of the problem document (`code`, +`domain`, `retry`, `next_step`, `params`, a structured `location`, `errors` items, `request_id`), a verdict's faults as +`errors[]`, and a failed run's problem as `run_error`, or `error` on the status tool (pipelex-mcp's `SPEC.md`, "Verdicts +and errors"). A skill still naming an old field would branch on something that never arrives. + +`validation_errors` is the one old name the workshop keeps: `mthds_save_method` and `mthds_publish_method` still carry +their verdict's faults under it, as problem items. So it is allowed in `pipelex-catalog`, the skill that reads those +two tools' verdicts, and refused everywhere else. """ from __future__ import annotations @@ -25,12 +30,19 @@ REPO_ROOT = Path(__file__).parents[2] TARGETS = ("prod", "codex", "mistral-vibe") -REPLACED_FIELD = re.compile(r"\b(error_type|error_domain|error_category|user_action|caller_facing_message|ErrorReport|UserActionKind)\b") +RUNTIME_REPORT_FIELD = re.compile(r"\b(error_type|error_domain|error_category|user_action|caller_facing_message|ErrorReport|UserActionKind)\b") +WORKSHOP_RETIRED_FIELD = re.compile( + r"\b(input_domain|retryable|failure_message|template_check_warning|method_not_published|method_version_not_found)\b" + r"|`hint`|\bhint verbatim\b|`failure`" + r"|class `(?:config|runtime)`|error of class|`config`|kind: \"(?:auth|role)\"" +) +SAVE_AND_PUBLISH_FIELD = re.compile(r"\bvalidation_errors\b") +SAVE_AND_PUBLISH_SKILL = "pipelex-catalog" class TestSkillErrorFields: @pytest.mark.parametrize("target_name", TARGETS) - def test_no_shipped_skill_file_names_a_replaced_error_field(self, target_name: str) -> None: + def test_no_shipped_skill_file_names_a_retired_error_field(self, target_name: str) -> None: """Every file a target ships under `skills/`, references and scripts included, as a user installs it.""" config = load_target_config(REPO_ROOT / "targets", target_name) skills_dir = resolve_output_dir(REPO_ROOT, config.source) / "skills" @@ -39,9 +51,46 @@ def test_no_shipped_skill_file_names_a_replaced_error_field(self, target_name: s named: list[str] = [] for path in shipped: + relative = path.relative_to(skills_dir) + patterns = [RUNTIME_REPORT_FIELD, WORKSHOP_RETIRED_FIELD] + if relative.parts[0] != SAVE_AND_PUBLISH_SKILL: + patterns.append(SAVE_AND_PUBLISH_FIELD) text = path.read_text(encoding="utf-8") for line_number, line in enumerate(text.splitlines(), 1): - for match in REPLACED_FIELD.finditer(line): - named.append(f"{path.relative_to(skills_dir)}:{line_number} names `{match.group(1)}`") + for pattern in patterns: + for match in pattern.finditer(line): + named.append(f"{relative}:{line_number} names `{match.group(0)}`") + + assert not named, f"{target_name}: a skill teaches an error field nobody sends any more: " + "; ".join(named) + + @pytest.mark.parametrize( + "line", + [ + '| `status: "error"`, class `input_domain` | fix the call |', + "surface the error's `hint` verbatim", + "Give `failure_message` **verbatim** first", + "a `config`-class error included", + 'as a `config` error tagged `kind: "role"`', + "only if `retryable: true`", + '| `status: "error"`, class `runtime` | report it |', + "refused as `method_not_published`", + "before acting on a `template_check_warning`", + ], + ) + def test_the_workshop_pattern_refuses_its_old_contract(self, line: str) -> None: + assert WORKSHOP_RETIRED_FIELD.search(line), f"the guard lets an old workshop field through: {line}" - assert not named, f"{target_name}: a skill teaches an error field the problem document replaced: " + "; ".join(named) + @pytest.mark.parametrize( + "line", + [ + '| `status: "error"`, `domain: "input"` | fix the call |', + "relay its `next_step` verbatim", + "Give the run's `run_error` **verbatim** first", + "on the summary's `retry_after_seconds` hint", + "a problem in the `account` domain included", + "refused as `pipelex.catalog.not_published`", + "before acting on a `pipelex.docgen.template_warning`", + ], + ) + def test_the_workshop_pattern_lets_the_problem_document_through(self, line: str) -> None: + assert not WORKSHOP_RETIRED_FIELD.search(line), f"the guard refuses a field the workshop sends: {line}" diff --git a/tests/unit/test_skill_guards.py b/tests/unit/test_skill_guards.py index 7cb1a0cf..2376e083 100644 --- a/tests/unit/test_skill_guards.py +++ b/tests/unit/test_skill_guards.py @@ -71,7 +71,7 @@ "Never refuse to explain a local bundle because the workshop is not connected.", "a narrower explanation, not a stop", "That stop is only for a target that lives on the platform", - "Same scope: on a local bundle a `config` error costs the verdict line and nothing else", + "Same scope: on a local bundle such a problem costs the verdict line and nothing else", "**This skill writes nothing of its own.** It saves no document and changes nothing in the bundle", "**Read them all before saying anything about any of them.**", "with the `method_id` and **no `output_dir`**", @@ -268,7 +268,7 @@ "**with the inputs' source and the keys the request replaced**", "**A saved run stays out of version control**", "**git never ignores a tracked path, so one still not ignored is not written until the user says so.**", - "Give `failure_message` **verbatim** first", + "Give the run's `run_error` **verbatim** first", "When the method holds a `PipeFunc`, name it as a suspect", "Per-pipe bisection is not this skill's.", "Do not re-run a failed method with altered inputs to see what happens — that spends credit on a guess.",