Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/<case>/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

Expand Down
8 changes: 4 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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.
Loading
Loading