From 885c1d3e2cfea5deefb4db5e0652580caaabefa8 Mon Sep 17 00:00:00 2001 From: Louis Choquel Date: Fri, 25 Sep 2026 17:32:28 +0200 Subject: [PATCH 1/2] =?UTF-8?q?fix/Doc-summarizer-sample=20=C2=B7=20L-2609?= =?UTF-8?q?04-863013=20(#12)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit doc_summarizer's sample linked a placeholder on a reserved .invalid host, so it could not run at any tag from v0.1.0 to v0.1.3; it now links the cookbook's CatOps deck at the cookbook's v0.18.0 tag, and a hosted run from the committed inputs.json completed. The release skill gains a fourth gate, check-samples.sh, which refuses a sample URL on a reserved domain or pinned to anything but a tag on GitHub (directly or through a redirect) and asks every other one for its first byte; docs/releasing.md and the README's contributor rules say the same. Advances L-260904-863013 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01AWN8BPDankpv7i3jeYUXpa --------- Co-authored-by: Claude Opus 5.5 --- .claude/skills/release/SKILL.md | 21 +-- .../skills/release/scripts/check-samples.sh | 153 ++++++++++++++++++ CHANGELOG.md | 6 + README.md | 1 + docs/releasing.md | 7 +- methods/doc_summarizer/inputs.json | 5 +- 6 files changed, 178 insertions(+), 15 deletions(-) create mode 100755 .claude/skills/release/scripts/check-samples.sh diff --git a/.claude/skills/release/SKILL.md b/.claude/skills/release/SKILL.md index 83e55b5..37252e4 100644 --- a/.claude/skills/release/SKILL.md +++ b/.claude/skills/release/SKILL.md @@ -3,20 +3,20 @@ name: release description: > Cut a release of methods, the public MTHDS method library at github.com/Pipelex/methods: the release/vX.Y.Z worktree, the lockstep bump of - every methods/*/METHODS.toml, the changelog entry, the format, lint and - validation gates, one commit, and a pull request to main whose merge creates - the annotated vX.Y.Z tag every pinned address resolves against. Use when the - user says "release", "cut a release", "bump version", "prepare a release", - "new version", "make a release", "ship it", "create release branch", - "promote dev to main", "tag the library", "snapshot the library", or wants a - change reachable at a new @vX.Y.Z address. Changelog content passed inline - ("/release Added a contract review method") becomes the entry. The merge is - landed by /ledger-land, never by this skill. + every methods/*/METHODS.toml, the changelog entry, the format, lint, + validation and sample gates, one commit, and a pull request to main whose + merge creates the annotated vX.Y.Z tag every pinned address resolves against. + Use when the user says "release", "cut a release", "bump version", "prepare a + release", "new version", "make a release", "ship it", "create release + branch", "promote dev to main", "tag the library", "snapshot the library", or + wants a change reachable at a new @vX.Y.Z address. Changelog content passed + inline ("/release Added a contract review method") becomes the entry. The + merge is landed by /ledger-land, never by this skill. --- # Releasing the method library -The procedure is the workspace release play, [`docs/workspace/releasing.md`](../../../../docs/workspace/releasing.md) at the workspace root — `../docs/workspace/releasing.md` from this repo's own root, which resolves the same from the main checkout and from any worktree. Read it first, then run it with what follows. The repo key is `methods`, the base is `dev`, and the pull request targets `main`. The release worktree is `_methods--release`, made with `wt add methods release --branch release/vX.Y.Z`. The repo declares no `.worktree.toml`, no `.worktreeinclude` and no Makefile, so `wt` resolves the base from `origin/dev` and provisions nothing: the gates run with the `pipelex` and `plxt` installed on the machine. The repo's own account of the scheme, the workflows and why they are built as they are is [`docs/releasing.md`](../../../docs/releasing.md). +The procedure is the workspace release play, [`docs/workspace/releasing.md`](../../../../docs/workspace/releasing.md) at the workspace root — `../docs/workspace/releasing.md` from this repo's own root, which resolves the same from the main checkout and from any worktree. Read it first, then run it with what follows. The repo key is `methods`, the base is `dev`, and the pull request targets `main`. The release worktree is `_methods--release`, made with `wt add methods release --branch release/vX.Y.Z`. The repo declares no `.worktree.toml`, no `.worktreeinclude` and no Makefile, so `wt` resolves the base from `origin/dev` and provisions nothing: the gates run with the `pipelex`, `plxt`, `curl` and `jq` installed on the machine. The repo's own account of the scheme, the workflows and why they are built as they are is [`docs/releasing.md`](../../../docs/releasing.md). ## What ships @@ -52,6 +52,7 @@ Run at the root of the worktree, in this order. Every one is blocking. 1. **Lockstep** — `grep -h '^version = ' methods/*/METHODS.toml | sort -u` must print exactly one line. Before the bump that line is the previous release's version, and a second line means a package reached `dev` declaring another one; the bump cures it, since it rewrites every manifest. **After the bump** it runs again and must print exactly `version = "X.Y.Z"`. 2. **Format and lint** — `plxt fmt --check`, then `plxt lint`, over every `.mthds` bundle and `METHODS.toml`. The repo carries no `plxt` configuration, so `plxt` reads the machine's own, `~/.pipelex/plxt.toml` when there is one. A red format check is cured by `plxt fmt`, which rewrites, and whatever it touched joins the release commit. A red lint is a bundle to fix on `dev` through an ordinary branch before the release is cut again. 3. **Every package validates** — `for d in methods/*/; do pipelex validate bundle "$d" >/dev/null || echo "✗ $d"; done` prints nothing when every package passes; re-run a failing one without the redirect to read why. It is the static validation and dry run the README asks of every contribution, and it spends no inference. A red package is fixed on `dev` through an ordinary branch, never inside the release commit. +4. **Every sample resolves** — `.claude/skills/release/scripts/check-samples.sh` reads every `url` in every `methods/*/inputs.json` and must print `✓` for each one. It refuses by name a host under a reserved domain (`.invalid`, `.test`, `.example`, `.localhost`, `example.com` and its siblings), which is what a generated inputs template leaves behind, and a `raw.githubusercontent.com` link whose ref is not a `v*` tag of its repository, which it asks GitHub with `git ls-remote` because a branch can be named like a version; it asks every other URL for its first byte and wants a `2xx`, and holds a URL that redirects, such as a `github.com/…/raw/…` link, to the same rules where it lands. It needs `curl`, `git` and `jq`, no API key, and spends no inference. Validation never fetches a sample, which is how `doc_summarizer` shipped a placeholder from `v0.1.0` to `v0.1.3`, and a tag freezes its samples for good. A red sample is fixed on `dev` through an ordinary branch, never inside the release commit. ## The release commit diff --git a/.claude/skills/release/scripts/check-samples.sh b/.claude/skills/release/scripts/check-samples.sh new file mode 100755 index 0000000..f9d0412 --- /dev/null +++ b/.claude/skills/release/scripts/check-samples.sh @@ -0,0 +1,153 @@ +#!/usr/bin/env bash +# Check that every URL a sample inputs.json links answers. +# +# check-samples.sh [inputs.json ...] +# +# With no argument it reads every methods/*/inputs.json of the checkout the +# script lives in, wherever it is run from; name files to check those instead. +# It takes every `url` value in each file, at any depth, and refuses one that +# is not an http(s) URL, one whose host is under a domain reserved for +# documentation and testing (.invalid, .test, .example, .localhost, and +# example.com, example.net, example.org), which is what a generated inputs +# template's placeholder looks like, and a raw.githubusercontent.com URL whose +# ref is not a v* tag, since a sample must not change under a library tag. A +# bare ref (///) is looked up with git ls-remote, since +# a branch can be named like a version: it must be a tag of that repository +# and not also a branch. Every other URL must answer a request for its first +# byte with a 2xx, and a URL that redirects is held to the same rules where it +# lands, which is how github.com's /raw/ and ?raw=true links are checked. No +# call spends inference. Prints one line per URL, and one per file jq cannot +# read, and exits non-zero when any line is a failure. +# +# Needs curl, git and jq. + +set -euo pipefail + +for arg in "$@"; do + if [[ "$arg" == -* ]]; then + echo "usage: $0 [inputs.json ...]" >&2 + exit 2 + fi + [ -f "$arg" ] || { echo "$arg: no such file" >&2; exit 2; } +done +for tool in curl git jq; do + command -v "$tool" >/dev/null || { echo "$tool is required" >&2; exit 2; } +done + +if [ "$#" -eq 0 ]; then + cd "$(dirname "$0")/../../../.." + shopt -s nullglob + set -- methods/*/inputs.json + shopt -u nullglob +fi + +errors=$(mktemp) +trap 'rm -f "$errors"' EXIT +failures=0 + +# Why a URL is refused before anything fetches it, or nothing when it is not. +refusal() { + local url=$1 rest host owner repo ref kind name spelled_as_tag refs + if [[ ! "$url" =~ ^[Hh][Tt][Tt][Pp][Ss]?:// ]]; then + echo "not an http(s) URL, so the hosted API cannot fetch it" + return + fi + rest=${url#*://} + host=${rest%%[/?#]*} + host=${host##*@} + host=${host%:*} + host=$(printf '%s' "$host" | tr '[:upper:]' '[:lower:]') + host=${host%.} + case "$host" in + invalid | *.invalid | test | *.test | example | *.example) + echo "$host is under a reserved top-level domain that never resolves: a placeholder, not a sample" + return + ;; + localhost | *.localhost) + echo "$host is the machine making the request, never a public host: a placeholder, not a sample" + return + ;; + example.com | *.example.com | example.net | *.example.net | example.org | *.example.org) + echo "$host is a reserved example domain: a placeholder, not a sample" + return + ;; + esac + if [ "$host" = raw.githubusercontent.com ]; then + # The path is ////, the ref possibly spelled refs/tags/. + IFS=/ read -r owner repo ref kind name _ <<<"${rest#*/}" + spelled_as_tag=false + if [ "$ref" = refs ]; then + if [ "$kind" != tags ]; then + echo "names refs/$kind/$name, which is not a tag, so the file can change under a library tag: link it at a v* tag of $owner/$repo" + return + fi + ref=$name + spelled_as_tag=true + fi + if [[ ! "$ref" =~ ^v[0-9] ]]; then + echo "names the ref '$ref', which is not a v* tag, so the file can change under a library tag: link it at a v* tag of $owner/$repo" + return + fi + # A bare ref is whatever GitHub resolves the name to, and a branch can be + # named like a version, so ask GitHub which one it is. + if [ "$spelled_as_tag" = false ]; then + if ! refs=$(GIT_TERMINAL_PROMPT=0 git ls-remote "https://github.com/$owner/$repo.git" "refs/tags/$ref" "refs/heads/$ref" 2>"$errors"); then + echo "cannot list the refs of $owner/$repo on GitHub: $(head -n 1 "$errors")" + return + fi + if [ -z "$(awk -v want="refs/tags/$ref" '$2 == want' <<<"$refs")" ]; then + echo "names '$ref', which is not a tag of $owner/$repo, so the file can change under a library tag: link it at a v* tag" + return + fi + if [ -n "$(awk -v want="refs/heads/$ref" '$2 == want' <<<"$refs")" ]; then + echo "names '$ref', which is both a tag and a branch of $owner/$repo: spell it refs/tags/$ref so the tag is what is served" + return + fi + fi + fi +} + +for file in "$@"; do + if ! urls=$(jq -r '.. | objects | .url? | strings' "$file" 2>"$errors"); then + echo "✗ $file — not valid JSON: $(head -n 1 "$errors")" + failures=$((failures + 1)) + continue + fi + while IFS= read -r url; do + [ -n "$url" ] || continue + reason=$(refusal "$url") + if [ -n "$reason" ]; then + echo "✗ $file: $url — $reason" + failures=$((failures + 1)) + continue + fi + if ! fetched=$(curl -sSL -r 0-0 --max-time 30 --retry 2 -o /dev/null \ + -w '%{http_code} %{num_redirects} %{url_effective}' "$url" 2>"$errors"); then + echo "✗ $file: $url — $(head -n 1 "$errors")" + failures=$((failures + 1)) + continue + fi + read -r code redirects effective <<<"$fetched" + if [[ "$code" != 2?? ]]; then + echo "✗ $file: $url — HTTP $code" + failures=$((failures + 1)) + continue + fi + # A link can reach raw GitHub through a redirect, as github.com's /raw/ and + # ?raw=true links do, so where it lands is held to the same rules. + if [ "$redirects" -gt 0 ]; then + reason=$(refusal "$effective") + if [ -n "$reason" ]; then + echo "✗ $file: $url — redirects to $effective, which fails: $reason" + failures=$((failures + 1)) + continue + fi + fi + echo "✓ $file: $url" + done <<<"$urls" +done + +if [ "$failures" -ne 0 ]; then + echo "$failures sample check(s) failed" >&2 + exit 1 +fi diff --git a/CHANGELOG.md b/CHANGELOG.md index a22be68..5e1ec27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [Unreleased] + +### Fixed + +- **`doc_summarizer`'s sample document**: its `inputs.json` links a real document, the cookbook's CatOps pitch deck at the cookbook's `v0.18.0` tag, where it named a placeholder host that never resolves. At `v0.1.3` and earlier the sample does not run: run it at `@v0.1.4` or later. + ## [v0.1.3] - 2026-09-25 ### Added diff --git a/README.md b/README.md index 357e98c..7aee7a9 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ Beyond that rule: - **Exports**: list the pipes you mean callers to use in `[exports.]`; unlisted pipes stay private to the package. - **It must validate**: `pipelex validate bundle methods//` must pass before you open a PR. - **Quality over quantity**: a method that actually runs, with a sample `inputs.json` where practical, beats a pile of stubs. Keep binary assets out of the package — link to hosted samples instead. +- **Samples must answer**: every URL in a sample `inputs.json` must resolve, and no release is cut while one does not. A file hosted on GitHub is linked at a tag, never at a branch, so the sample cannot change under a library tag; the library's own samples use the [Pipelex cookbook](https://github.com/Pipelex/pipelex-cookbook)'s tags. ## License diff --git a/docs/releasing.md b/docs/releasing.md index df2bab9..9891ca5 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -22,8 +22,9 @@ A release is a `release/vX.Y.Z` branch cut from `dev` and merged into `main` by 1. On the release branch, set the version in every manifest: `perl -pi -e 's/^version = ".*"/version = "X.Y.Z"/' methods/*/METHODS.toml`. Then `grep -h '^version = ' methods/*/METHODS.toml | sort -u` must print exactly one line, the version being released. 2. In the same commit, turn the `## [Unreleased]` section of `CHANGELOG.md` into the release's entry, `## [vX.Y.Z] - YYYY-MM-DD`, leaving no `[Unreleased]` heading behind. 3. Before committing, check the bundles: `plxt fmt --check` and `plxt lint` over every `.mthds` and `METHODS.toml`, and `pipelex validate bundle methods//` for every package. -4. Open the pull request into `main`. Its checks refuse a manifest that does not declare the branch's version, and a changelog without the entry. -5. The merge creates the tag and the GitHub Release. Once the tag exists, check that every package runs by its address at it: `.claude/skills/release/scripts/check-addresses.sh vX.Y.Z`, with `PIPELEX_API_KEY` set, asks the hosted API to fetch and validate each package at the tag, spends no inference, and must print `✓` for every one. +4. Check that every sample resolves: `.claude/skills/release/scripts/check-samples.sh` reads every `url` in every `methods/*/inputs.json`, refuses a placeholder on a reserved domain such as `.invalid` and a `raw.githubusercontent.com` link whose ref is not a `v*` tag of its repository, whether linked directly or reached by a redirect such as a `github.com/…/raw/…` link, asks every other URL for its first byte, spends no inference, and must print `✓` for every one. Validation never fetches a sample, and a tag freezes its samples for good, so this is the one moment a dead sample link can be caught before it ships. A sample file hosted on GitHub is a house-owned asset linked at one of the cookbook's tags, never at a branch and never at a tag of this repository, so it cannot change under a library tag. +5. Open the pull request into `main`. Its checks refuse a manifest that does not declare the branch's version, and a changelog without the entry. +6. The merge creates the tag and the GitHub Release. Once the tag exists, check that every package runs by its address at it: `.claude/skills/release/scripts/check-addresses.sh vX.Y.Z`, with `PIPELEX_API_KEY` set, asks the hosted API to fetch and validate each package at the tag, spends no inference, and must print `✓` for every one. The Pipelex team runs these steps with the repository's `/release` skill for Claude Code, [`.claude/skills/release/SKILL.md`](../.claude/skills/release/SKILL.md), inside the workspace release play that every Pipelex repository shares. @@ -35,7 +36,7 @@ The Pipelex team runs these steps with the repository's `/release` skill for Cla | `changelog-check.yml` | pull request → `main` | `CHANGELOG.md` has `## [vX.Y.Z] - …` for that version, and no `[Unreleased]` heading survives | | `github-release.yml` | push to `main`, and `workflow_dispatch` from `main` | creates the annotated tag on the release pull request's merge commit, and the GitHub Release | -The pull-request checks act only on a head matching `release/vX.Y.Z` exactly and pass trivially on anything else. They read the branch name from an environment variable rather than splicing it into their script, since in a public repository anyone can open a pull request from a branch named with shell syntax. Nothing in CI formats, lints or validates a bundle: step 3 above runs on the releaser's machine and nowhere else. +The pull-request checks act only on a head matching `release/vX.Y.Z` exactly and pass trivially on anything else. They read the branch name from an environment variable rather than splicing it into their script, since in a public repository anyone can open a pull request from a branch named with shell syntax. Nothing in CI formats, lints or validates a bundle, or checks a sample link: steps 3 and 4 above run on the releaser's machine and nowhere else. A check of the sample links in CI would also catch a dead link on an ordinary pull request, but it would make every pull request depend on third-party hosts answering, and the release is the moment a sample becomes immutable. ### Why the tagger creates the tag itself diff --git a/methods/doc_summarizer/inputs.json b/methods/doc_summarizer/inputs.json index 3fc1ae0..4177cb2 100644 --- a/methods/doc_summarizer/inputs.json +++ b/methods/doc_summarizer/inputs.json @@ -2,7 +2,8 @@ "document": { "concept": "native.Document", "content": { - "url": "https://mock-d6ae6957.invalid/ee7a682e-4944-4e1e-81b4-178fdd2a6788" + "url": "https://raw.githubusercontent.com/Pipelex/pipelex-cookbook/v0.18.0/assets/presentations/CatOps.pdf", + "mime_type": "application/pdf" } } -} \ No newline at end of file +} From 4484dcf59018f5170b4c5f4a9ec1c12c625356ab Mon Sep 17 00:00:00 2001 From: Louis Choquel Date: Fri, 25 Sep 2026 17:33:59 +0200 Subject: [PATCH 2/2] Release v0.1.4 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AWN8BPDankpv7i3jeYUXpa --- CHANGELOG.md | 2 +- methods/cv_analyzer/METHODS.toml | 2 +- methods/doc_summarizer/METHODS.toml | 2 +- methods/documents/METHODS.toml | 2 +- methods/image_generation/METHODS.toml | 2 +- methods/invoice_extraction/METHODS.toml | 2 +- methods/slide_designer/METHODS.toml | 2 +- methods/table_extraction/METHODS.toml | 2 +- methods/text_stats/METHODS.toml | 2 +- methods/tweet_optimizer/METHODS.toml | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e1ec27..db18fd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [Unreleased] +## [v0.1.4] - 2026-09-25 ### Fixed diff --git a/methods/cv_analyzer/METHODS.toml b/methods/cv_analyzer/METHODS.toml index 1b3d83a..fb36b13 100644 --- a/methods/cv_analyzer/METHODS.toml +++ b/methods/cv_analyzer/METHODS.toml @@ -2,7 +2,7 @@ name = "cv_analyzer" display_name = "CV Analyzer" address = "github.com/Pipelex/methods" -version = "0.1.3" +version = "0.1.4" description = "End-to-end candidate screening: extract a CV and a job offer, analyze the match, then either generate tailored interview questions or draft a courteous refusal email." authors = ["Evotis S.A.S"] license = "MIT" diff --git a/methods/doc_summarizer/METHODS.toml b/methods/doc_summarizer/METHODS.toml index 5482a92..69f730b 100644 --- a/methods/doc_summarizer/METHODS.toml +++ b/methods/doc_summarizer/METHODS.toml @@ -2,7 +2,7 @@ name = "doc_summarizer" display_name = "Document Summarizer" address = "github.com/Pipelex/methods" -version = "0.1.3" +version = "0.1.4" description = "Deep document summarization: profile the document and extract importance-ranked key points in parallel, then synthesize a structured summary with themes and open questions." authors = ["Evotis S.A.S"] license = "MIT" diff --git a/methods/documents/METHODS.toml b/methods/documents/METHODS.toml index f604b58..91019af 100644 --- a/methods/documents/METHODS.toml +++ b/methods/documents/METHODS.toml @@ -2,7 +2,7 @@ name = "documents" display_name = "Documents" address = "github.com/Pipelex/methods" -version = "0.1.3" +version = "0.1.4" description = "Document extraction methods for text, images, and page views." authors = ["Evotis S.A.S"] license = "MIT" diff --git a/methods/image_generation/METHODS.toml b/methods/image_generation/METHODS.toml index 80f984b..fa49167 100644 --- a/methods/image_generation/METHODS.toml +++ b/methods/image_generation/METHODS.toml @@ -2,7 +2,7 @@ name = "image_generation" display_name = "Image Generation" address = "github.com/Pipelex/methods" -version = "0.1.3" +version = "0.1.4" description = "Image generation methods: render a description directly, or refine it into an optimized image prompt first." authors = ["Evotis S.A.S"] license = "MIT" diff --git a/methods/invoice_extraction/METHODS.toml b/methods/invoice_extraction/METHODS.toml index 69f008f..09519f2 100644 --- a/methods/invoice_extraction/METHODS.toml +++ b/methods/invoice_extraction/METHODS.toml @@ -2,7 +2,7 @@ name = "invoice_extraction" display_name = "Invoice Extraction" address = "github.com/Pipelex/methods" -version = "0.1.3" +version = "0.1.4" description = "Extract structured invoice data from a document: classify each page as bill or receipt, then extract amounts, VAT, vendor and buyer details using both the OCR text and the page view." authors = ["Evotis S.A.S"] license = "MIT" diff --git a/methods/slide_designer/METHODS.toml b/methods/slide_designer/METHODS.toml index d6a8e2a..66b140e 100644 --- a/methods/slide_designer/METHODS.toml +++ b/methods/slide_designer/METHODS.toml @@ -2,7 +2,7 @@ name = "slide_designer" display_name = "Slide Designer" address = "github.com/Pipelex/methods" -version = "0.1.3" +version = "0.1.4" description = "Turn a rough slide-deck brief into design proposals: polish the brief, generate multiple visual themes, render a mockup image for each, and compose an HTML report presenting them all." authors = ["Evotis S.A.S"] license = "MIT" diff --git a/methods/table_extraction/METHODS.toml b/methods/table_extraction/METHODS.toml index 998fe38..feaeb54 100644 --- a/methods/table_extraction/METHODS.toml +++ b/methods/table_extraction/METHODS.toml @@ -2,7 +2,7 @@ name = "table_extraction" display_name = "Table Extraction" address = "github.com/Pipelex/methods" -version = "0.1.3" +version = "0.1.4" description = "Extract a data table from a screenshot into faithful HTML, then review the result against the image to correct text and formatting." authors = ["Evotis S.A.S"] license = "MIT" diff --git a/methods/text_stats/METHODS.toml b/methods/text_stats/METHODS.toml index 760d9b3..67b3e20 100644 --- a/methods/text_stats/METHODS.toml +++ b/methods/text_stats/METHODS.toml @@ -2,7 +2,7 @@ name = "text_stats" display_name = "Text Stats" address = "github.com/Pipelex/methods" -version = "0.1.3" +version = "0.1.4" description = "Deterministic text statistics computed in pure Python: character, word, sentence and paragraph counts, vocabulary richness, most frequent words, and estimated reading and speaking times, reported as Markdown." authors = ["Evotis S.A.S"] license = "MIT" diff --git a/methods/tweet_optimizer/METHODS.toml b/methods/tweet_optimizer/METHODS.toml index 15e9fe6..a6b0092 100644 --- a/methods/tweet_optimizer/METHODS.toml +++ b/methods/tweet_optimizer/METHODS.toml @@ -2,7 +2,7 @@ name = "tweet_optimizer" display_name = "Tweet Optimizer" address = "github.com/Pipelex/methods" -version = "0.1.3" +version = "0.1.4" description = "Optimize a tech tweet: score the draft for fluffiness, cringiness, humblebragging and vagueness, then rewrite it in your own writing style following Twitter/X best practices." authors = ["Evotis S.A.S"] license = "MIT"