Document PipeFunc authoring, with a validated example - #11
thomashebrard wants to merge 2 commits into
Conversation
The skills carried a four-line PipeFunc stub inherited from the CLI era, and it described the local-install registry model — nothing an agent could act on when the target is the hosted API. The `writing-mthds.md` variant additionally gave `function_name` as a dotted import path, which registration names never are. Add `skills/shared/writing-pipe-funcs.md`, a shared reference rendered per target: the function contract, structures as return types, the working-memory accessors, file organization, the sandbox's library set and no-network rule, why validation cannot catch any of it, and how a PipeFunc method actually runs. Structures come from codegen — `codegen types --target python-structures`, via the CLI, its `build structures` alias, or `POST /v1/codegen`. Verified byte-identical across the CLI and the deployed API. A PipeFunc imports its return type from the generated `structures.py` by concept code. Route it from the skills: `pipelex-design` treats a PipeFunc leaf as incomplete until its Python exists, `pipelex-edit` keeps the two halves in step across renames and concept reshapes, `pipelex-explain` reads the `.py` to explain the step. Add `examples/support-digest/` — three PipeFunc, two PipeLLM, one PipeSequence — written to the reference, then validated and executed against the pipelex runtime rather than written from memory. Test fixtures now derive their shared-file sets from SHARED_TEMPLATES, so adding a shared reference no longer breaks unrelated tests. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Confidence Score: 4/5The PR appears safe to merge after correcting the non-blocking documentation contradiction about whether the example ships The implementation, generated target files, and worked example are internally consistent, but the changelog and repository overview describe the example’s generated-structure packaging in direct conflict with the files added by the PR. Files Needing Attention: CHANGELOG.md, CLAUDE.md Prompt To Fix All With AI### Issue 1
CHANGELOG.md:8
**Contradictory structures packaging guidance**
This entry says the example ships no `structures.py`, but the PR adds a generated `examples/support-digest/structures.py` and its README instructs authors to ship and regenerate it. This contradiction can lead readers to omit the module imported by the example's PipeFuncs.
```suggestion
- **Worked example** under `examples/support-digest/`: a weekly support digest built from three `PipeFunc`, two `PipeLLM`, and one `PipeSequence`, written to the new reference and then validated and executed against the `pipelex` runtime. It ships its code-generated `structures.py` and `codegen.lock`; its README documents regeneration and what hosted validation will not catch.
```
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "Document PipeFunc authoring, with a vali..." | Re-trigger Greptile |
| ### Added | ||
|
|
||
| - **PipeFunc authoring guide**: New shared reference `skills/shared/writing-pipe-funcs.md`, rendered per target, covering the whole surface the skills previously left undocumented — the function contract (`@pipe_func()`, the single `working_memory` parameter, the required return annotation), structure classes as return types (`from structures import <ConceptCode>`, projected by codegen and shipped in the bundle, never hand-written), the working-memory accessors, how to split the Python across files, the libraries the sandbox actually has (standard library plus `pipelex`, `pandas`, `openpyxl`), the no-network rule, why validation cannot catch any of it, and why only a registered method can run its Python. | ||
| - **Worked example** under `examples/support-digest/`: a weekly support digest built from three `PipeFunc`, two `PipeLLM`, and one `PipeSequence`, written to the new reference and then validated and executed against the `pipelex` runtime. It ships no `structures.py` — the runtime generates that module, and shipping one would override it — and its README documents the local bootstrap detour and what hosted validation will not catch. |
There was a problem hiding this comment.
Contradictory structures packaging guidance
This entry says the example ships no structures.py, but the PR adds a generated examples/support-digest/structures.py and its README instructs authors to ship and regenerate it. This contradiction can lead readers to omit the module imported by the example's PipeFuncs.
| - **Worked example** under `examples/support-digest/`: a weekly support digest built from three `PipeFunc`, two `PipeLLM`, and one `PipeSequence`, written to the new reference and then validated and executed against the `pipelex` runtime. It ships no `structures.py` — the runtime generates that module, and shipping one would override it — and its README documents the local bootstrap detour and what hosted validation will not catch. | |
| - **Worked example** under `examples/support-digest/`: a weekly support digest built from three `PipeFunc`, two `PipeLLM`, and one `PipeSequence`, written to the new reference and then validated and executed against the `pipelex` runtime. It ships its code-generated `structures.py` and `codegen.lock`; its README documents regeneration and what hosted validation will not catch. |
Prompt To Fix With AI
This is a comment left during a code review.
Path: CHANGELOG.md
Line: 8
Comment:
**Contradictory structures packaging guidance**
This entry says the example ships no `structures.py`, but the PR adds a generated `examples/support-digest/structures.py` and its README instructs authors to ship and regenerate it. This contradiction can lead readers to omit the module imported by the example's PipeFuncs.
```suggestion
- **Worked example** under `examples/support-digest/`: a weekly support digest built from three `PipeFunc`, two `PipeLLM`, and one `PipeSequence`, written to the new reference and then validated and executed against the `pipelex` runtime. It ships its code-generated `structures.py` and `codegen.lock`; its README documents regeneration and what hosted validation will not catch.
```
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
5 issues found across 39 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="examples/support-digest/assemble.py">
<violation number="1" location="examples/support-digest/assemble.py:25">
P2: When a ticket category contains `|` or a line break, `_stats_table` emits invalid Markdown because it interpolates the raw category into a table cell. Escape Markdown table metacharacters and normalize line breaks before constructing each row.</violation>
<violation number="2" location="examples/support-digest/assemble.py:33">
P3: For non-zero counts the headline always renders "N SLA breach(es)", producing "1 SLA breach(es)" and "2 SLA breach(es)" — grammatically broken output that gets pasted into a team channel. Pluralize properly by count (e.g. handle 1 vs many), or drop the "(es)" suffix.</violation>
</file>
<file name="CLAUDE.md">
<violation number="1" location="CLAUDE.md:54">
P3: The tree comment claims `support-digest` "ships no structures.py by design", but the example does ship it: `structures.py` is tracked in git (git ls-files lists it) and the example's OWN README says "`structures.py` is already here, so nothing to generate". The comment is self-contradictory and misleads a reader about the example's contents. Drop the "ships no structures.py by design" clause (or reword to note the generated, drift-checked file is committed).</violation>
</file>
<file name="examples/support-digest/README.md">
<violation number="1" location="examples/support-digest/README.md:47">
P3: The "Only allowed libraries" rule omits `openpyxl` from the allowed set. The canonical reference (`templates/skills/shared/writing-pipe-funcs.md.j2`) defines the sandbox set as "Python's standard library, `pipelex`, `pandas`, and `openpyxl`. Nothing else." Restating it as just "`pandas` and the standard library" is an incomplete restatement of the authoritative rule a reader must rely on, and could suggest `openpyxl` (a listed spreadsheet library) is forbidden.</violation>
</file>
<file name="CHANGELOG.md">
<violation number="1" location="CHANGELOG.md:8">
P2: The release note states the `examples/support-digest/` example "ships no `structures.py` — the runtime generates that module, and shipping one would override it — and its README documents the local bootstrap detour." That is contradicted by the same PR's example: `structures.py` is committed and tracked in the repo (`examples/support-digest/structures.py`, 131 lines, present in `git ls-files`), its README says "`structures.py` is already here, so nothing to generate", and the PR description itself says the example "uses generated structures.py and codegen.lock". The changelog implies a deliberately absent file when the example actually ships the generated module, which will mislead anyone reading the release notes about how the example is meant to be used.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| header = "| Category | Tickets | Median hours | Mean CSAT |\n| --- | ---: | ---: | ---: |" | ||
| if not stats.by_category: | ||
| return f"{header}\n| _no tickets this week_ | 0 | 0 | 0 |" | ||
| rows = [f"| {stat.category} | {stat.ticket_count} | {stat.median_resolution_hours} | {stat.mean_satisfaction} |" for stat in stats.by_category] |
There was a problem hiding this comment.
P2: When a ticket category contains | or a line break, _stats_table emits invalid Markdown because it interpolates the raw category into a table cell. Escape Markdown table metacharacters and normalize line breaks before constructing each row.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At examples/support-digest/assemble.py, line 25:
<comment>When a ticket category contains `|` or a line break, `_stats_table` emits invalid Markdown because it interpolates the raw category into a table cell. Escape Markdown table metacharacters and normalize line breaks before constructing each row.</comment>
<file context>
@@ -0,0 +1,55 @@
+ header = "| Category | Tickets | Median hours | Mean CSAT |\n| --- | ---: | ---: | ---: |"
+ if not stats.by_category:
+ return f"{header}\n| _no tickets this week_ | 0 | 0 | 0 |"
+ rows = [f"| {stat.category} | {stat.ticket_count} | {stat.median_resolution_hours} | {stat.mean_satisfaction} |" for stat in stats.by_category]
+ return "\n".join([header, *rows])
+
</file context>
| ### Added | ||
|
|
||
| - **PipeFunc authoring guide**: New shared reference `skills/shared/writing-pipe-funcs.md`, rendered per target, covering the whole surface the skills previously left undocumented — the function contract (`@pipe_func()`, the single `working_memory` parameter, the required return annotation), structure classes as return types (`from structures import <ConceptCode>`, projected by codegen and shipped in the bundle, never hand-written), the working-memory accessors, how to split the Python across files, the libraries the sandbox actually has (standard library plus `pipelex`, `pandas`, `openpyxl`), the no-network rule, why validation cannot catch any of it, and why only a registered method can run its Python. | ||
| - **Worked example** under `examples/support-digest/`: a weekly support digest built from three `PipeFunc`, two `PipeLLM`, and one `PipeSequence`, written to the new reference and then validated and executed against the `pipelex` runtime. It ships no `structures.py` — the runtime generates that module, and shipping one would override it — and its README documents the local bootstrap detour and what hosted validation will not catch. |
There was a problem hiding this comment.
P2: The release note states the examples/support-digest/ example "ships no structures.py — the runtime generates that module, and shipping one would override it — and its README documents the local bootstrap detour." That is contradicted by the same PR's example: structures.py is committed and tracked in the repo (examples/support-digest/structures.py, 131 lines, present in git ls-files), its README says "structures.py is already here, so nothing to generate", and the PR description itself says the example "uses generated structures.py and codegen.lock". The changelog implies a deliberately absent file when the example actually ships the generated module, which will mislead anyone reading the release notes about how the example is meant to be used.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At CHANGELOG.md, line 8:
<comment>The release note states the `examples/support-digest/` example "ships no `structures.py` — the runtime generates that module, and shipping one would override it — and its README documents the local bootstrap detour." That is contradicted by the same PR's example: `structures.py` is committed and tracked in the repo (`examples/support-digest/structures.py`, 131 lines, present in `git ls-files`), its README says "`structures.py` is already here, so nothing to generate", and the PR description itself says the example "uses generated structures.py and codegen.lock". The changelog implies a deliberately absent file when the example actually ships the generated module, which will mislead anyone reading the release notes about how the example is meant to be used.</comment>
<file context>
@@ -1,5 +1,22 @@
+### Added
+
+- **PipeFunc authoring guide**: New shared reference `skills/shared/writing-pipe-funcs.md`, rendered per target, covering the whole surface the skills previously left undocumented — the function contract (`@pipe_func()`, the single `working_memory` parameter, the required return annotation), structure classes as return types (`from structures import <ConceptCode>`, projected by codegen and shipped in the bundle, never hand-written), the working-memory accessors, how to split the Python across files, the libraries the sandbox actually has (standard library plus `pipelex`, `pandas`, `openpyxl`), the no-network rule, why validation cannot catch any of it, and why only a registered method can run its Python.
+- **Worked example** under `examples/support-digest/`: a weekly support digest built from three `PipeFunc`, two `PipeLLM`, and one `PipeSequence`, written to the new reference and then validated and executed against the `pipelex` runtime. It ships no `structures.py` — the runtime generates that module, and shipping one would override it — and its README documents the local bootstrap detour and what hosted validation will not catch.
+- **Codegen as the structures path**: the guide documents generating `structures.py` through `codegen types --target python-structures` — the `pipelex codegen` CLI, its `build structures` alias, or `POST /v1/codegen` — verified byte-identical across the CLI and the deployed API. It notes that the API route reads `.mthds` only, so it generates for a bundle that already declares PipeFuncs, while the local CLI in `direct` mode cannot.
+- **PipeFunc routing in the skills**: `pipelex-design` now treats a `PipeFunc` leaf as an incomplete pipe until its Python is written, `pipelex-edit` keeps the pipe entry and its function in step across renames and concept reshapes, and `pipelex-explain` reads the bundle's `.py` to explain what a `PipeFunc` step does.
</file context>
| - **Worked example** under `examples/support-digest/`: a weekly support digest built from three `PipeFunc`, two `PipeLLM`, and one `PipeSequence`, written to the new reference and then validated and executed against the `pipelex` runtime. It ships no `structures.py` — the runtime generates that module, and shipping one would override it — and its README documents the local bootstrap detour and what hosted validation will not catch. | |
| - **Worked example** under `examples/support-digest/`: a weekly support digest built from three `PipeFunc`, two `PipeLLM`, and one `PipeSequence`, written to the new reference and then validated and executed against the `pipelex` runtime. It ships the codegen'd `structures.py` and `codegen.lock` (the `POST /v1/codegen` output) so nothing needs generating locally, and its README documents the local bootstrap detour and what hosted validation will not catch. |
| pipelex-codex/ # Codex plugin (generated, checked in) | ||
| pipelex-vibe/ # Mistral Vibe target (generated, checked in; loaded via skill_paths) | ||
| examples/ | ||
| └── support-digest/ # Worked PipeFunc example (3 PipeFunc, 2 PipeLLM, 1 PipeSequence) — validated against the pipelex runtime; ships no structures.py by design |
There was a problem hiding this comment.
P3: The tree comment claims support-digest "ships no structures.py by design", but the example does ship it: structures.py is tracked in git (git ls-files lists it) and the example's OWN README says "structures.py is already here, so nothing to generate". The comment is self-contradictory and misleads a reader about the example's contents. Drop the "ships no structures.py by design" clause (or reword to note the generated, drift-checked file is committed).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At CLAUDE.md, line 54:
<comment>The tree comment claims `support-digest` "ships no structures.py by design", but the example does ship it: `structures.py` is tracked in git (git ls-files lists it) and the example's OWN README says "`structures.py` is already here, so nothing to generate". The comment is self-contradictory and misleads a reader about the example's contents. Drop the "ships no structures.py by design" clause (or reword to note the generated, drift-checked file is committed).</comment>
<file context>
@@ -49,6 +50,8 @@ templates/ # SOURCE OF TRUTH — all .j2 templates live here
pipelex-codex/ # Codex plugin (generated, checked in)
pipelex-vibe/ # Mistral Vibe target (generated, checked in; loaded via skill_paths)
+examples/
+└── support-digest/ # Worked PipeFunc example (3 PipeFunc, 2 PipeLLM, 1 PipeSequence) — validated against the pipelex runtime; ships no structures.py by design
scripts/
├── gen_skill_docs.py # Template renderer (multi-target)
</file context>
| └── support-digest/ # Worked PipeFunc example (3 PipeFunc, 2 PipeLLM, 1 PipeSequence) — validated against the pipelex runtime; ships no structures.py by design | |
| +└── support-digest/ # Worked PipeFunc example (3 PipeFunc, 2 PipeLLM, 1 PipeSequence) — validated against the pipelex runtime; ships generated structures.py and codegen.lock |
|
|
||
| **Sibling imports work.** `compute_stats.py` does `from _tickets import ...`; every directory holding a `.py` in the bundle is on the path when registration runs. | ||
|
|
||
| **Only allowed libraries.** `pandas` and the standard library. No network, no other dependency. |
There was a problem hiding this comment.
P3: The "Only allowed libraries" rule omits openpyxl from the allowed set. The canonical reference (templates/skills/shared/writing-pipe-funcs.md.j2) defines the sandbox set as "Python's standard library, pipelex, pandas, and openpyxl. Nothing else." Restating it as just "pandas and the standard library" is an incomplete restatement of the authoritative rule a reader must rely on, and could suggest openpyxl (a listed spreadsheet library) is forbidden.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At examples/support-digest/README.md, line 47:
<comment>The "Only allowed libraries" rule omits `openpyxl` from the allowed set. The canonical reference (`templates/skills/shared/writing-pipe-funcs.md.j2`) defines the sandbox set as "Python's standard library, `pipelex`, `pandas`, and `openpyxl`. Nothing else." Restating it as just "`pandas` and the standard library" is an incomplete restatement of the authoritative rule a reader must rely on, and could suggest `openpyxl` (a listed spreadsheet library) is forbidden.</comment>
<file context>
@@ -0,0 +1,78 @@
+
+**Sibling imports work.** `compute_stats.py` does `from _tickets import ...`; every directory holding a `.py` in the bundle is on the path when registration runs.
+
+**Only allowed libraries.** `pandas` and the standard library. No network, no other dependency.
+
+## `structures.py` and `codegen.lock`
</file context>
| **Only allowed libraries.** `pandas` and the standard library. No network, no other dependency. | |
| **Only allowed libraries.** `pandas`, `openpyxl`, and the standard library (`pipelex` itself is the framework, not a dependency). No network, no other dependency. |
| """One line a reader can take in without opening the table.""" | ||
| if stats.total_tickets == 0: | ||
| return "No tickets closed this week." | ||
| breaches = "no SLA breaches" if breach_count == 0 else f"{breach_count} SLA breach(es)" |
There was a problem hiding this comment.
P3: For non-zero counts the headline always renders "N SLA breach(es)", producing "1 SLA breach(es)" and "2 SLA breach(es)" — grammatically broken output that gets pasted into a team channel. Pluralize properly by count (e.g. handle 1 vs many), or drop the "(es)" suffix.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At examples/support-digest/assemble.py, line 33:
<comment>For non-zero counts the headline always renders "N SLA breach(es)", producing "1 SLA breach(es)" and "2 SLA breach(es)" — grammatically broken output that gets pasted into a team channel. Pluralize properly by count (e.g. handle 1 vs many), or drop the "(es)" suffix.</comment>
<file context>
@@ -0,0 +1,55 @@
+ """One line a reader can take in without opening the table."""
+ if stats.total_tickets == 0:
+ return "No tickets closed this week."
+ breaches = "no SLA breaches" if breach_count == 0 else f"{breach_count} SLA breach(es)"
+ return (
+ f"{stats.total_tickets} tickets closed, median {stats.median_resolution_hours}h "
</file context>
The guide led with `pipelex codegen types`, a CLI this plugin deliberately does not ship, and framed validation and runs in CLI terms. The MCP surface has no codegen tool, so the reachable route is the HTTP one. - generate structures via `POST /v1/codegen` with `PIPELEX_API_KEY`; the local CLI is a parenthetical, explicitly not to be depended on - validation section speaks in terms of `mthds_validate` and its `is_valid` verdict, and notes the edit hook is the same blind engine - run section names `mthds_run`, `method_id`, and states plainly that no tool here registers a method - example README separates "how this was verified" (local pipelex checkout) from what using it requires (nothing local) Record the gap in docs/decisions.md: an `mthds_codegen` tool on the pipelex-mcp side would make PipeFunc authoring self-contained within the skills. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
4 issues found across 6 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="templates/skills/shared/writing-pipe-funcs.md.j2">
<violation number="1" location="templates/skills/shared/writing-pipe-funcs.md.j2:70">
P3: A `is_valid: false` body means the `.mthds` itself did not resolve</violation>
</file>
<file name="examples/support-digest/README.md">
<violation number="1" location="examples/support-digest/README.md:72">
P3: This line says "the figures below came out of the actual functions," but the README contains no figures or example output tables anywhere after this point (or in the file at all). The reference dangles. Either include the expected digest/output it promises or drop the clause.</violation>
</file>
<file name="pipelex-vibe/skills/shared/writing-pipe-funcs.md">
<violation number="1" location="pipelex-vibe/skills/shared/writing-pipe-funcs.md:70">
P3: Minor wording: "A `is_valid: false` body" should read "An `is_valid: false` body".</violation>
<violation number="2" location="pipelex-vibe/skills/shared/writing-pipe-funcs.md:70">
P2: The documented procedure writes only the response `lock` field to codegen.lock, but the verified codegen.lock in this PR's own example (examples/support-digest/codegen.lock) also embeds an `[[artifacts]]` table carrying the structures.py path and content_hash. If the API's `lock` field holds just the fingerprints and not that artifacts metadata (as 'artifacts[]' being a separate response field implies), following these instructions produces a codegen.lock that doesn't match the real artifact. Confirm what `lock` actually contains and state explicitly that it already includes the artifacts metadata (or that the artifacts table must be merged), so an agent generates the correct file.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| "files": [{ "content": "<main.mthds contents>", "source": "main.mthds" }] } | ||
| ``` | ||
|
|
||
| A 200 carries `is_valid: true`, `artifacts[]` (one entry, `path: "structures.py"`), and a `lock`. Write `artifacts[0].content` to `structures.py` in the bundle and `lock` to `codegen.lock` beside it. A `is_valid: false` body means the `.mthds` itself did not resolve — fix that first, the same way you would a failed validate. |
There was a problem hiding this comment.
P2: The documented procedure writes only the response lock field to codegen.lock, but the verified codegen.lock in this PR's own example (examples/support-digest/codegen.lock) also embeds an [[artifacts]] table carrying the structures.py path and content_hash. If the API's lock field holds just the fingerprints and not that artifacts metadata (as 'artifacts[]' being a separate response field implies), following these instructions produces a codegen.lock that doesn't match the real artifact. Confirm what lock actually contains and state explicitly that it already includes the artifacts metadata (or that the artifacts table must be merged), so an agent generates the correct file.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At pipelex-vibe/skills/shared/writing-pipe-funcs.md, line 70:
<comment>The documented procedure writes only the response `lock` field to codegen.lock, but the verified codegen.lock in this PR's own example (examples/support-digest/codegen.lock) also embeds an `[[artifacts]]` table carrying the structures.py path and content_hash. If the API's `lock` field holds just the fingerprints and not that artifacts metadata (as 'artifacts[]' being a separate response field implies), following these instructions produces a codegen.lock that doesn't match the real artifact. Confirm what `lock` actually contains and state explicitly that it already includes the artifacts metadata (or that the artifacts table must be merged), so an agent generates the correct file.</comment>
<file context>
@@ -59,29 +59,27 @@ Class names are the concept codes verbatim: concept `TicketStats` becomes `class
-The response carries artifacts[] (structures.py) plus a codegen.lock; write both into the bundle. pipelex build structures is a thin alias of the same command, so it is the same output under an older name.
+A 200 carries is_valid: true, artifacts[] (one entry, path: "structures.py"), and a lock. Write artifacts[0].content to structures.py in the bundle and lock to codegen.lock beside it. A is_valid: false body means the .mthds itself did not resolve — fix that first, the same way you would a failed validate.
-The API route takes .mthds only and never imports your Python, so it generates for a bundle that already declares PipeFuncs. The local CLI does not: in direct mode it validates each function_name against the registry at load, which needs your .py imported, which needs the structures module you are trying to create. Generate through the API, or generate before the PipeFunc pipes exist.
</file context>
</details>
| "files": [{ "content": "<main.mthds contents>", "source": "main.mthds" }] } | ||
| ``` | ||
|
|
||
| A 200 carries `is_valid: true`, `artifacts[]` (one entry, `path: "structures.py"`), and a `lock`. Write `artifacts[0].content` to `structures.py` in the bundle and `lock` to `codegen.lock` beside it. A `is_valid: false` body means the `.mthds` itself did not resolve — fix that first, the same way you would a failed validate. |
There was a problem hiding this comment.
P3: A is_valid: false body means the .mthds itself did not resolve
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At templates/skills/shared/writing-pipe-funcs.md.j2, line 70:
<comment>A `is_valid: false` body means the `.mthds` itself did not resolve</comment>
<file context>
@@ -59,29 +59,27 @@ Class names are the concept codes verbatim: concept `TicketStats` becomes `class
-The response carries artifacts[] (structures.py) plus a codegen.lock; write both into the bundle. pipelex build structures is a thin alias of the same command, so it is the same output under an older name.
+A 200 carries is_valid: true, artifacts[] (one entry, path: "structures.py"), and a lock. Write artifacts[0].content to structures.py in the bundle and lock to codegen.lock beside it. A is_valid: false body means the .mthds itself did not resolve — fix that first, the same way you would a failed validate.
-The API route takes .mthds only and never imports your Python, so it generates for a bundle that already declares PipeFuncs. The local CLI does not: in direct mode it validates each function_name against the registry at load, which needs your .py imported, which needs the structures module you are trying to create. Generate through the API, or generate before the PipeFunc pipes exist.
</file context>
</details>
| Not a requirement for using it — this is what was run to confirm the reference is accurate, against a local `pipelex` checkout: | ||
|
|
||
| - `pipelex validate bundle .` → successfully validated. Local `direct` mode runs the full PipeFunc checks (function found in the registry, return type matching the output concept) that the hosted API skips, so it is the strictest available check. | ||
| - `pipelex run bundle . --pipe compute_ticket_stats -i inputs.json` → executed for real; the figures below came out of the actual functions. |
There was a problem hiding this comment.
P3: This line says "the figures below came out of the actual functions," but the README contains no figures or example output tables anywhere after this point (or in the file at all). The reference dangles. Either include the expected digest/output it promises or drop the clause.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At examples/support-digest/README.md, line 72:
<comment>This line says "the figures below came out of the actual functions," but the README contains no figures or example output tables anywhere after this point (or in the file at all). The reference dangles. Either include the expected digest/output it promises or drop the clause.</comment>
<file context>
@@ -48,31 +48,32 @@ async def compute_ticket_stats(working_memory: WorkingMemory) -> TicketStats:
+Not a requirement for using it — this is what was run to confirm the reference is accurate, against a local `pipelex` checkout:
+
+- `pipelex validate bundle .` → successfully validated. Local `direct` mode runs the full PipeFunc checks (function found in the registry, return type matching the output concept) that the hosted API skips, so it is the strictest available check.
+- `pipelex run bundle . --pipe compute_ticket_stats -i inputs.json` → executed for real; the figures below came out of the actual functions.
+- `POST /v1/codegen` against the deployed API returned bytes identical to the local generator — same `crate_fingerprint`, same `content_hash`.
</file context>
| - `pipelex run bundle . --pipe compute_ticket_stats -i inputs.json` → executed for real; the figures below came out of the actual functions. | |
| - `pipelex run bundle . --pipe compute_ticket_stats -i inputs.json` → executed for real. |
| "files": [{ "content": "<main.mthds contents>", "source": "main.mthds" }] } | ||
| ``` | ||
|
|
||
| A 200 carries `is_valid: true`, `artifacts[]` (one entry, `path: "structures.py"`), and a `lock`. Write `artifacts[0].content` to `structures.py` in the bundle and `lock` to `codegen.lock` beside it. A `is_valid: false` body means the `.mthds` itself did not resolve — fix that first, the same way you would a failed validate. |
There was a problem hiding this comment.
P3: Minor wording: "A is_valid: false body" should read "An is_valid: false body".
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At pipelex-vibe/skills/shared/writing-pipe-funcs.md, line 70:
<comment>Minor wording: "A `is_valid: false` body" should read "An `is_valid: false` body".</comment>
<file context>
@@ -59,29 +59,27 @@ Class names are the concept codes verbatim: concept `TicketStats` becomes `class
-The response carries artifacts[] (structures.py) plus a codegen.lock; write both into the bundle. pipelex build structures is a thin alias of the same command, so it is the same output under an older name.
+A 200 carries is_valid: true, artifacts[] (one entry, path: "structures.py"), and a lock. Write artifacts[0].content to structures.py in the bundle and lock to codegen.lock beside it. A is_valid: false body means the .mthds itself did not resolve — fix that first, the same way you would a failed validate.
-The API route takes .mthds only and never imports your Python, so it generates for a bundle that already declares PipeFuncs. The local CLI does not: in direct mode it validates each function_name against the registry at load, which needs your .py imported, which needs the structures module you are trying to create. Generate through the API, or generate before the PipeFunc pipes exist.
</file context>
</details>
Why
The skills carried a four-line
PipeFuncstub inherited from the CLI era, describing the local-install registry model — nothing an agent could act on when the target is the hosted API.writing-mthds.mdwas worse: it gavefunction_nameas a dotted import path (my_package.text_utils.capitalize), which registration names never are, and told the reader to avoidPipeFuncunless a function was already registered.What
New shared reference —
skills/shared/writing-pipe-funcs.md, rendered per target (Claude, Codex, Vibe):@pipe_func()called, oneworking_memory: WorkingMemoryparameter passed by keyword, a requiredStuffContent/ListContent[...]return annotation, sync or asynccodegen types --target python-structures, through the CLI, itsbuild structuresalias, orPOST /v1/codegen. A PipeFunc imports its return type from the generatedstructures.pyby concept codecontent_type=/item_type=pipelex+pandas+openpyxl, nothing else — and the no-network ruleRouting —
pipelex-designtreats aPipeFuncleaf as incomplete until its Python exists;pipelex-editkeeps the pipe entry and its function in step across renames and concept reshapes;pipelex-explainreads the.pyto explain the step.Fixes — the stale
func_registryprose and the dottedfunction_nameexample in both the language reference andwriting-mthds.md.Example —
examples/support-digest/— threePipeFunc, twoPipeLLM, onePipeSequence. Written to the reference, then validated and executed against thepipelexruntime rather than written from memory. Ships its codegen'dstructures.py+codegen.lock.Tests — fixtures now derive their shared-file sets from
SHARED_TEMPLATES, so adding a shared reference no longer breaks unrelated tests.Verification
pipelex validate bundle examples/support-digest→ Successfully validated (local mode runs the full PipeFunc registry and return-type checks that hosted mode skips)POST /v1/codegenon the deployed dev API returns bytes identical to the local CLI — samecrate_fingerprint, samecontent_hashmake checkandmake agent-testgreen across all three targetsNote for review
The runtime also has an always-qualified structure-class spelling (
<domain>__<Concept>). It is on its way out, so this guide deliberately does not teach it — recorded indocs/decisions.md. One consequence worth a second opinion: with concepts declared as one-liners, the.mthdsno longer describes field shapes, so the generatedstructures.pybecomes the source of truth for them.🤖 Generated with Claude Code
Summary by cubic
Documents how to author
PipeFuncmethods for the hosted API and fixes prior guidance onfunction_name. Replaces CLI-centric advice with API-backed flows and ships a validated example bundle.skills/shared/writing-pipe-funcs.md(rendered per target) covering the Python contract (@pipe_func(), singleworking_memory: WorkingMemoryparam, required return annotation), importing structure classes from generatedstructures.py, working‑memory accessors, sandbox libraries (pipelex,pandas,openpyxl) and no‑network rule, limits of validation, and the run path viamthds_run/method_id.POST /v1/codegenusingPIPELEX_API_KEY; describes validation viamthds_validate; notes no tool here registers a method. Records the gap for anmthds_codegentool indocs/decisions.md.writing-mthds.md:function_nameis a flat registration name; examples now describePipeFuncas running custom Python for deterministic work.examples/support-digest/(threePipeFunc, twoPipeLLM, onePipeSequence) withstructures.pyandcodegen.lock; README separates how the example was verified from what users need to run it.pipelex-design,pipelex-edit,pipelex-explain) to treat aPipeFuncleaf as two‑part and to read the.pywhen explaining; build docs show the new shared reference per target.scripts/gen_skill_docs.pyrenders the new template; tests derive shared files fromSHARED_TEMPLATESto avoid fixture breakage.Adoption
function_namevalues and ship the matching Python in the same bundle, decorated with@pipe_func()and takingworking_memory: WorkingMemory; return the pipe’s output structure class.structures.pyviaPOST /v1/codegen..mthdsand.pyin sync; validation does not check the Python. Avoid relying on a local CLI.Written for commit b5e322a. Summary will update on new commits.