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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
### Added

- **`pipelex-integrate` — wire an MTHDS method into a Python or TypeScript codebase.** Given a local bundle, a published `method_ref` at a tag, or a catalog `method_id`, and a project, the skill picks the codegen target by audience (`ts-zod`; `python-pydantic` for a hosted-API consumer, `python-structures` for a Pipelex host), has the workshop's `mthds_codegen` write the generated tree into one dedicated directory per method through its `output_dir` arm — no artifact byte ever passes through the model, and a refused write is never worked around by writing bytes from the conversation — excludes that tree, and the drift-gate script it copies into the project, from the project's formatters and linters *before* either exists while keeping the type checker's coverage as it is, records a `sources.json` sidecar (selector, target, pipe signature, the bundle directory the call site loads, and a hash for every `.mthds` file under it) so a second run is a refresh and a bundle change — a file edited, removed or added — is detectable, wires an offline drift gate into the project's existing check — `scripts/codegen-check.mjs` over `@pipelex/sdk`'s `runCodegenCheck` for TypeScript, `scripts/codegen_check.py` over `pipelex-sdk`'s `run_codegen_check` (run in the project's own environment) for a Python consumer, each on an SDK raised to the skill's floor when the project pins an older one (`@pipelex/sdk` 0.17.0, `pipelex-sdk` 0.10.0), neither adding the `pipelex` runtime and neither reading its own failure to run as drift: an SDK that cannot be imported or fails while it loads, or a check that throws, exits `2`, no verdict — and writes one typed call-site module per method over `startAndWaitForResult` / `start_and_wait` and the generated binder or model. The call site is typed from the main pipe's signature on the validate verdict. A refresh keeps the gate current as well: it verifies the tooling exclusions first, installs a gate script the project lacks and wires it, re-copies one that differs from the shipped reference — which, kept out of the formatters and linters, only an out-of-date script does — and adds the refreshed method's directory to the gate command when it is missing, leaving every other method's registration as it is. A project made from a Pipelex template keeps its own codegen harness: the skill runs the project's `codegen` script or `make add-method`, which scaffolds a local bundle in one command on a project whose `make add-method` takes a bundle path, and never writes a second layout beside the first. Two things it refuses outright, because both are silent: generating a second method into a directory that already holds another method's tree (every method of a target emits the same file names, so that overwrites the first and reports no orphan), and reaching a project the workshop was not launched in (a path inside the workshop is legal wherever it points, so containment is read before the first write and a tree that landed beside the wrong project is never moved across). A write whose only fault is orphans is not one of them: stamped files the new lock does not list make the drift check report the tree non-current, but with nothing else drifted the generation itself is sound, so the skill reads `orphans[]` and `drifts[]` rather than the verdict, finishes the integration, and reports the orphan paths by name — never deleted, with a dedicated directory per generation as the fix and the gate counting each orphan as a drift until the directory holds one generation. Any other drift ends the run. One upstream defect it names rather than patches: the `ts-zod` emitter writes `binder.ts`'s sibling import without a file extension, which a plain Node ESM project rejects at type-check and at runtime while a bundler resolution accepts — the generated tree is stamped and hashed, so the fix is the emitter's and the skill says so. Ships `references/typescript.md`, `references/python.md`, `references/codegen-check.mjs` and `references/codegen_check.py`.
- **`pipelex-scaffold` — the front door to a project that does not exist yet.** Two branches and no templates of its own: a Pipelex template, or the ecosystem's initializer (`uv init --package`, `npm create next-app@latest`, …) when the user wants their framework. A TypeScript web app around a method is the demo-free method app, the `webapp-js/` directory of `pipelex-method-apps`: the skill copies that directory out of a shallow clone into the destination, commits it once as it came, runs the template's **own** `make create` with the user's bundle, catalog id or package address, which names the project after the method, scaffolds its form and result view, writes `.env.local` and runs `make all`, and then starts the dev server on a free port and reports its URL first, once one request has proven the page answers. The page's Server Actions spend the key for whoever reaches them, so the server is started only from a copy whose dev script binds it to loopback, and the start command stops it before the first request if `lsof` shows it listening anywhere else, or if its port has not opened by the end of the wait. A copy already in the working directory is checked before git is initialized in it, so the template's own checkout, which sits inside the family repository, is never taken for a copy. The `pipelex-starter-js` gallery is acquired only when the user names it. A starter — the gallery, or `pipelex-starter-python` for a CLI or service — is acquired as a fresh-history local clone by default or through `gh repo create --template` after confirmation, committed once as it came, then renamed by the clone's **own** `bootstrap` skill, read from its `SKILL.md` and never reimplemented. The starters and the initializer end with the env-file convention, the key filled only from the shell environment and never asked for in the conversation, the base URL copied from the environment whenever the shell sets one, with a key or without — a key is refused by every plane but the one that issued it and a keyless self-hosted runner is a plane too, so neither a dev or staging key nor a self-hosted project is left pointing at production's URL — with the report naming the plane the file points at and warning, when it is not production, that a key from `app.pipelex.com` will be refused there, and a hand-off to `/pipelex-integrate`. It is the plugin's third MCP-free skill, and never handles a key itself: the method app's gesture reads the key from the shell or from an `.env.local` the user writes. Ships `references/starters.md`, which sets the method app, the gallery and the Python starter side by side, and `references/initializers.md`.
- **`pipelex-scaffold` — the front door to a project that does not exist yet.** Two branches and no templates of its own: a Pipelex template, or the ecosystem's initializer (`uv init --package`, `npm create next-app@latest`, …) when the user wants their framework. A TypeScript web app around a method is the demo-free method app, the `webapp-js/` directory of `pipelex-method-apps`: the skill copies that directory out of a shallow clone into the destination, commits it once as it came, runs the template's **own** `make create` with the user's bundle, catalog id or package address, which names the project after the method, scaffolds its form and result view, writes `.env.local` and runs `make all`, and then starts the dev server on a free port and reports its URL first, once one request has proven the page answers. The report relays every warning the gesture printed, starting with an MIT `LICENSE` that still names the template's copyright holder, and a clone interrupted by Ctrl-C or by the harness leaves no temporary directory beside the project. The page's Server Actions spend the key for whoever reaches them, so the server is started only from a copy whose dev script binds it to loopback, and the start command stops it before the first request if `lsof` shows it listening anywhere else, or if its port has not opened by the end of the wait. A copy already in the working directory is checked before git is initialized in it, so the template's own checkout, which sits inside the family repository, is never taken for a copy. The `pipelex-starter-js` gallery is acquired only when the user names it. A starter — the gallery, or `pipelex-starter-python` for a CLI or service — is acquired as a fresh-history local clone by default or through `gh repo create --template` after confirmation, committed once as it came, then renamed by the clone's **own** `bootstrap` skill, read from its `SKILL.md` and never reimplemented. The starters and the initializer end with the env-file convention, the key filled only from the shell environment and never asked for in the conversation, the base URL copied from the environment whenever the shell sets one, with a key or without — a key is refused by every plane but the one that issued it and a keyless self-hosted runner is a plane too, so neither a dev or staging key nor a self-hosted project is left pointing at production's URL — with the report naming the plane the file points at and warning, when it is not production, that a key from `app.pipelex.com` will be refused there, and a hand-off to `/pipelex-integrate`. It is the plugin's third MCP-free skill, and never handles a key itself: the method app's gesture reads the key from the shell or from an `.env.local` the user writes. Ships `references/starters.md`, which sets the method app, the gallery and the Python starter side by side, and `references/initializers.md`.
- **`pipelex-vibe/mcp/vibe-mcp.toml` — the Mistral Vibe target bakes the workshop launcher**: Vibe has no plugin manifest, so the target now ships the `npx -y @pipelex/mcp@latest` launcher as a `[[mcp_servers]]` stdio entry to append to the end of `~/.vibe/config.toml`, rendered from the same `[vars.mcp_server]` block as the Claude and Codex manifests and enforced by `make check`. Write your API key into the entry's `env` table, because Vibe spawns stdio servers with a minimal environment and never sees an exported `PIPELEX_API_KEY`; the MCP-backed skills' Vibe stop message now points at the fragment and says so, and their Vibe auth line no longer claims the server reads the session environment. Before appending, delete the `mcp_servers = []` line a new Vibe config carries and any `pipelex` server registered by hand: either leftover stops Vibe from starting. Vibe records its configuration, that key included, in every session log under `~/.vibe/logs/session/`, so redact the key before sharing one.
- **`pipelex-synthetic-inputs` — a skill that renders the files a method needs, from code.** PDFs through `reportlab` (canvas letters, multi-page Platypus reports, tables, and a composed line-item document whose totals come from its items) and PNGs through `Pillow` and `matplotlib` in four categories: `chart` (bar, line, pie, scatter), `diagram` (a node/edge list laid out on a grid with clipped arrows), `document_scan` (an A4-at-150-dpi page put through a seeded skew/tint/grain/vignette post-process, for OCR and document-understanding methods) and `screenshot` (window chrome, sidebar, stat tiles, and a status-badged table or card grid). Word and Excel come along from `pipelex-inputs`. No AI is involved anywhere, and only packages whose licences are compatible with MIT are used. **Photographs and handwriting are deliberately out of scope** — code cannot render either to a standard a vision model would accept, so the skill says so and asks for a real file instead of handing a method an imitation. It is MCP-free, the second such skill after `pipelex-explain`, and it installs what it needs itself: `uv` with ephemeral packages, or a venv it creates under the user's cache directory when `uv` is absent. Nothing is installed into the project, and installing a *tool* always asks first.
- **The recipes refuse to render a file that would be silently wrong.** A recipe is copied and adapted, so the content block is where things go wrong: each one now bounds its content against the page it is drawing on and stops with the cure rather than exiting 0 on a file that lies. A `document_scan` whose items overrun the page, a `screenshot` whose rows run off the canvas, a `diagram` with two nodes in one grid cell, an unsubstituted `<output_dir>` still in the path — every one of these used to print success and hand a method an input missing exactly the field it was meant to read. Line-item descriptions wrap instead of overprinting the quantity beside them, the PDF table recipe sizes its columns instead of drawing them off the paper, and every recipe renders beside its target and renames on success, so a crash can no longer truncate a file the user already had.
Expand All @@ -18,6 +18,7 @@
- **`pipelex-inputs` delegates file generation instead of doing it inline.** (Breaking) Its Document Generation section and Fallback Strategy block are gone, and the `native.Image` / `native.Document` strategy rows now delegate to `pipelex-synthetic-inputs`. "Generate File Inputs" is the delegation contract — the request fields to pass, the bare path that comes back and goes into `inputs.json`, and what happens when the factory cannot deliver: that one input is left unfilled with the reason in the report, and the rest of the flow continues. Anyone relying on the inline recipes should read them in the new skill's `references/`, where they are deeper and now executed by tests.
- **Tooling:** Pinned `ruff` to an exact `0.16.4`, replacing the `>=0.6.8` floor. The exact pin matches what the Ruff VS Code extension now bundles, which matters because Ruff 0.16 lints `pyproject.toml` itself: the extension syncs the config file to the language server, and a pre-0.16 binary parses it as Python source and paints phantom `invalid-syntax` diagnostics on lines like `requires-python`. A floor let the editor and the CLI resolve to different binaries; an exact pin cannot. This is a dev dependency, so nothing shipped changes, and the upgrade produced no lint findings and no reformatting.
- **Tooling — continuous integration.** The repo runs GitHub Actions on a pull request for the first time: `make check` and `make agent-test` on every one, a branch-flow guard carrying the workspace's closed prefix set, and version and changelog gates on a release-shaped pull request only. The shipped synthetic-inputs recipes run nightly, on demand, and on a pull request that touches their sources. No ruleset requires any of these checks, so they advise rather than block, and nothing runs on a merge. Nothing shipped changes; `docs/ci.md` is the account.
- **Tooling — `make check` refuses argument placeholders in a skill body.** Before the model reads a `SKILL.md`, Claude Code replaces `$ARGUMENTS` and `$0`, `$1`, … with the words the skill was invoked with, so a shell block containing one of those tokens reaches the model as a different command. The build now fails when any target's rendered `SKILL.md` contains one. No released skill contained one, so nothing shipped changes.

### Fixed

Expand Down
Loading
Loading