Skip to content

Document PipeFunc authoring, with a validated example - #11

Open
thomashebrard wants to merge 2 commits into
devfrom
docs/pipefunc-authoring-guide
Open

thomashebrard wants to merge 2 commits into
devfrom
docs/pipefunc-authoring-guide

Conversation

@thomashebrard

@thomashebrard thomashebrard commented Aug 13, 2026

Copy link
Copy Markdown
Member

Why

The skills carried a four-line PipeFunc stub 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.md was worse: it gave function_name as a dotted import path (my_package.text_utils.capitalize), which registration names never are, and told the reader to avoid PipeFunc unless a function was already registered.

What

New shared reference — skills/shared/writing-pipe-funcs.md, rendered per target (Claude, Codex, Vibe):

  • the function contract — @pipe_func() called, one working_memory: WorkingMemory parameter passed by keyword, a required StuffContent/ListContent[...] return annotation, sync or async
  • structures via codegencodegen types --target python-structures, through the CLI, its build structures alias, or POST /v1/codegen. A PipeFunc imports its return type from the generated structures.py by concept code
  • the working-memory accessor table, including the keyword-only content_type= / item_type=
  • when to split the Python across files, and when not to
  • the sandbox's library set — stdlib + pipelex + pandas + openpyxl, nothing else — and the no-network rule
  • why validation catches none of it, and how a PipeFunc method actually runs

Routingpipelex-design treats a PipeFunc leaf as incomplete until its Python exists; pipelex-edit keeps the pipe entry and its function in step across renames and concept reshapes; pipelex-explain reads the .py to explain the step.

Fixes — the stale func_registry prose and the dotted function_name example in both the language reference and writing-mthds.md.

Example — 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. Ships its codegen'd structures.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-digestSuccessfully validated (local mode runs the full PipeFunc registry and return-type checks that hosted mode skips)
  • both compute pipe funcs executed for real; figures correct, including excluding unrated tickets from the CSAT mean
  • POST /v1/codegen on the deployed dev API returns bytes identical to the local CLI — same crate_fingerprint, same content_hash
  • make check and make agent-test green across all three targets

Note 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 in docs/decisions.md. One consequence worth a second opinion: with concepts declared as one-liners, the .mthds no longer describes field shapes, so the generated structures.py becomes the source of truth for them.

🤖 Generated with Claude Code


Summary by cubic

Documents how to author PipeFunc methods for the hosted API and fixes prior guidance on function_name. Replaces CLI-centric advice with API-backed flows and ships a validated example bundle.

  • Adds a shared guide skills/shared/writing-pipe-funcs.md (rendered per target) covering the Python contract (@pipe_func(), single working_memory: WorkingMemory param, required return annotation), importing structure classes from generated structures.py, working‑memory accessors, sandbox libraries (pipelex, pandas, openpyxl) and no‑network rule, limits of validation, and the run path via mthds_run/method_id.
  • Aligns to a CLI‑free posture: generate structures with POST /v1/codegen using PIPELEX_API_KEY; describes validation via mthds_validate; notes no tool here registers a method. Records the gap for an mthds_codegen tool in docs/decisions.md.
  • Fixes the language reference and writing-mthds.md: function_name is a flat registration name; examples now describe PipeFunc as running custom Python for deterministic work.
  • Adds examples/support-digest/ (three PipeFunc, two PipeLLM, one PipeSequence) with structures.py and codegen.lock; README separates how the example was verified from what users need to run it.
  • Updates skills (pipelex-design, pipelex-edit, pipelex-explain) to treat a PipeFunc leaf as two‑part and to read the .py when explaining; build docs show the new shared reference per target.
  • Tooling/tests: scripts/gen_skill_docs.py renders the new template; tests derive shared files from SHARED_TEMPLATES to avoid fixture breakage.

Adoption

  • Use flat function_name values and ship the matching Python in the same bundle, decorated with @pipe_func() and taking working_memory: WorkingMemory; return the pipe’s output structure class.
  • Generate and import return types from structures.py via POST /v1/codegen.
  • Keep .mthds and .py in sync; validation does not check the Python. Avoid relying on a local CLI.

Written for commit b5e322a. Summary will update on new commits.

Review in cubic

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>
@greptile-apps

greptile-apps Bot commented Aug 13, 2026

Copy link
Copy Markdown

Confidence Score: 4/5

The PR appears safe to merge after correcting the non-blocking documentation contradiction about whether the example ships structures.py.

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

Comment thread CHANGELOG.md
### 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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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.

Suggested change
- **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.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>

Comment thread CHANGELOG.md
### 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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Suggested change
- **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.

Comment thread CLAUDE.md
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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Suggested change
└── 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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Suggested change
**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)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Suggested change
- `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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant