Skip to content

Releases: vlastimilbures/promptmend

v0.25.0

Choose a tag to compare

@github-actions github-actions released this 14 Oct 12:35
Immutable release. Only release title and notes can be modified.
47d65e9

Changed

  • setup on a terminal always opens the full-screen wizard: --provider and --profile
    preselect that choice, --deploy puts the focus on the install button, and --no-deploy
    and --no-smoke-test leave out those steps, instead of switching to a line-by-line mode (#244). --plain is now
    the same as --non-interactive; line-by-line questions are gone, and without a terminal
    (stdin or stdout) setup exits 3 unless one of them is given.
  • The interface reloads faster after each change: it asks Espanso for its folder and runs
    each launcher-lookup command once per reload instead of up to three times (#242).
  • promptmend --help describes the tool in one sentence instead of a developer note, and
    the config, profiles and history command lists give config show, migrate,
    rollback, profiles migrate and history prune a one-line summary; each
    command's own --help keeps the full text (#247).

Removed

  • The shell command, the terminal command line with completion and live help (#239). Run
    each command in your terminal as it is, or use the interface.
  • Home's command line in the interface (the c key) and its Recipes… button (#239). Every
    button's tooltip and every result still show the command it runs; Home still lists this
    session's commands and a few useful ones, and Copy last copies the latest.
  • The prompt-toolkit dependency, used only by the shell command (#239).
  • The interface's intro screen and its setting PROMPT_UI_INTRO (#245): the interface opens
    straight on Home. A saved or environment PROMPT_UI_INTRO is now ignored (doctor and
    config validate do not flag it; config unset refuses it, so delete a leftover line in
    config.toml by hand), and promptmend ui --no-intro is still accepted and does nothing. The Settings tab loses its Interface group.
  • The Diagnostics tab's import-time check of the CLI (#245).
  • The Diagnostics tab's table of every setting and its source (#245); the Settings tab and
    promptmend config show list each setting and where it comes from, and config show also
    names what each value overrides.
  • The pre-1.0 migration code (#246): config retire, config migrate --from,
    setup --migrate-from, the interface's Previous install screen (Home's "Previous install…"
    and the setup wizard's "Earlier install…"), and doctor's previous_install check (its
    warning about another promptmend first on PATH stays, as path_shadow). To move from
    a checkout install, copy its .env into the config folder and run config migrate, and
    copy edited profiles with profiles migrate --checkout PATH (docs/install.md, "From a
    checkout install").
    config rollback still puts back a checkout's .env that an earlier config retire moved.
  • Deploy no longer retires the match/base.yml that versions before 0.9 installed (#246): if
    it is still there, delete it by hand; promptmend espanso status lists it as yours.

Fixed

  • Usage history: a recorded run and doctor read history.spool and history.lost only
    under their lock, so on Windows they can no longer make another run's update of those files
    fail and lose that record, and a run that started before a management command moved the
    old prompt-workflow data folder no longer creates that folder again (that run's record is
    dropped) (#241).
  • A TLS certificate failure (a corporate proxy, a self-signed endpoint) is reported at once
    instead of being retried a second later: the retry could not succeed, delayed the marker
    and added a second record to the usage history (#247).
  • Setup's Done step no longer says "Match files: not installed" when the only files that
    differ are ones you edited and kept, which the Espanso step already says it leaves alone;
    it says how many of them were kept.
  • Setup's Next no longer gets stuck on the provider, profile and API keys steps while
    PROMPTMEND_ENV is set: it says the choice is not saved (settings stay in that file) and
    moves on; the keys step and the Done checklist say to add each key to that file.
  • Setup logs config unset when picking the default removed the setting, instead of a
    config set it did not run.
  • The Profiles tab's "Migrate from checkout" asks for the checkout's folder when none was
    found, instead of naming a --checkout flag the interface cannot pass.
  • Saving a setting or a key no longer replaces a symlinked config.toml or secrets.toml
    with a plain file: the file the link points to is written, so a copy kept in a dotfiles
    repo keeps getting the changes (#236).
  • improve --copy no longer loses the rewrite when the copy fails: the error marker is
    followed by the rewrite, as with PROMPT_OUTPUT=clipboard, and the history records
    clipboard_failed.
  • A reply in a code fence that the model then cut off (output limit) or stopped early now
    has its fence removed too, when the closing fence arrived before the stop; the note that it
    stopped early stays at the end. --copy copies the rewrite without that note, as
    PROMPT_OUTPUT=clipboard does.
  • An unexpected error's marker, or a library's ValueError, no longer pastes a key its
    message quotes: such a word is described (<redacted, N chars>) instead, and the whole
    message when the secret spans several words (Bearer …, password: …, a spaced card
    number). A failed copy's message is treated the same way.
  • improve --source stdin reads at most one character past the 50,000-character limit, so
    piping a huge file is refused at once (Input is too long (over 50000 chars)) instead of
    being loaded whole first.
  • promptmend config rollback puts each .env back before it moves config.toml and
    secrets.toml into the backup, so a trigger that fires during the rollback, or a .env
    that cannot be put back, still runs on the saved settings and keys instead of the defaults
    (#238).
  • When promptmend config migrate fails and cannot undo one of its own writes, the error
    now names the reason the migration failed, then could not undo: <file>, instead of only
    the error of the undo step. The migration record is then kept, and the message asks to
    run promptmend config rollback, which removes what the migration left (#238).

v0.24.0

Choose a tag to compare

@github-actions github-actions released this 08 Oct 10:24
Immutable release. Only release title and notes can be modified.
5082e8a

Added

  • promptmend setup in a terminal now opens a full-screen setup, one step at a time:
    welcome, earlier settings (only when there is a .env or an earlier checkout install),
    provider and profile picked from a list that says what each is and which triggers use it,
    the API keys, Espanso's match files in words (not installed yet, up to date, you edited it)
    with an install button, the stub test, and a checklist of what is left with how to try
    -i-. Home's "Setup…" opens it, and a bare promptmend opens it by itself once while
    nothing is set up. setup --plain (or any of --provider, --profile, --migrate-from,
    --deploy/--no-deploy, --no-smoke-test) asks line by line as before;
    --non-interactive is unchanged.

Fixed

  • setup asks for every key the triggers need, not only the chosen provider's: picking
    Ollama no longer skips OPENROUTER_API_KEY, which -i- still needs, and no longer ends
    with "Setup finished" while -i- cannot work.
  • setup run again with the same choices no longer rewrites config.toml.

Changed

  • setup line by line lists the providers and profiles with what each does, shows each
    match file's state in words, says "Not installed" (not "Dry run") when you answer no, and
    ends with how to try -i- or how many things are left to do.

v0.23.0

Choose a tag to compare

@github-actions github-actions released this 08 Oct 08:07
Immutable release. Only release title and notes can be modified.
07ed069

Changed

  • config show and the other commands that list settings show a key only as <set> or
    <not set>, no longer with its length (#222).
  • Interface: in the Settings list, u (as config unset) puts a setting back to its default
    or opens Remove key; r now reloads there too, as on every other tab, so a reload can no
    longer undo a setting (#215).
  • Faster start, most of all on Windows with endpoint scanning (#223): promptmend --version
    answers before the CLI loads (108 modules instead of 221 on macOS), and the triggers load
    httpx only for the provider call and the clipboard library only when they touch the
    clipboard (149 modules up to the call instead of 221).
  • The install scripts (install.ps1, install_windows.ps1, install_macos.sh) compile the
    bytecode at install, so the first run after an install is no longer the slow one (#216).
  • doctor's keys check names the triggers that need a missing key, read from the match
    files Espanso has (or, before a deploy, the ones a deploy would write): -i-, -iok-, -ip-, -if- use OpenRouter, but OPENROUTER_API_KEY is not set. PROMPT_PROVIDER only counts for a
    bare promptmend improve and the Try tab, and alone it is a warning; its data gains
    triggers (#217).
  • Interface: PROMPT_PROVIDER moved from Output to the Models group of the Settings tab, and
    its help says what it affects (a bare promptmend improve and the Try tab) (#217).
  • doctor's new local_servers check (information only) and the Triggers tab's State column
    say needs Ollama / needs LM Studio when a deployed local trigger's server does not
    answer. It asks only a server on this machine, with one short request; the deploy is
    unchanged: -il- and -ilm- stay active, -ic- stays commented out (#220).
  • promptmend stats prints one line on the history before the numbers; the full explanation
    and the notes moved to --verbose (the JSON is unchanged). A real Try tab run is listed as
    trigger -try-, and a bare promptmend improve as no trigger (direct call) instead of
    (none) (#222).
  • Interface: Home shows "Previous install…" only while there is one to offer (#222).
  • install.ps1's next steps name promptmend (the interface) too (#222).

Fixed

  • doctor no longer warns about the launcher on Windows when the match files call the same
    path written with / (or in another case) as this install (#212).
  • The deployed prompts-template.yml no longer has the CLI path pasted into its header
    comment (#214).
  • Interface: the Triggers tab shows the new states (in sync, or missing after a detach)
    as soon as a deploy or detach has written the files, without pressing r and without
    waiting for Espanso's restart (#215).
  • Usage history: a write that misses its time budget (the first one on a slow machine, or
    under antivirus or endpoint scanning) is no longer lost. It waits in history.spool in the
    data folder (the same metadata columns, at most 100 records) until the next recorded run,
    promptmend stats, promptmend history export or promptmend doctor stores it.
    history.lost now counts only records that could not be kept at all. doctor's history
    warning says why and what to do, and its data gains spooled (#213).
  • doctor's cli check names the .exe on Windows, as the install check does (#222).
  • doctor says no calls yet instead of 0 call(s) recorded in … while the history file
    does not exist (#222).
  • The deploy diff (espanso status --diff, Triggers "Show diff") says (missing) instead of
    (on disk) for a file that is not there yet (#222).
  • Windows: PromptMend no longer reads Espanso's output, which espansod.exe writes to the
    terminal instead of to PromptMend (#209, #210, #211). The config folder is worked out as
    Espanso does (a portable .espanso folder next to the running espansod.exe, else
    %APPDATA%\espanso), so a portable Espanso gets the triggers; "running" is Espanso's
    named pipe, so doctor no longer calls a stopped Espanso running; Espanso is found in the
    running process, on PATH, in %LOCALAPPDATA%\Programs\Espanso or its uninstall entry,
    so a stale Windows Terminal PATH no longer reports it missing. A restart after a deploy
    runs Espanso in a hidden console of its own: quitting the interface no longer hangs, and
    Ctrl+C or closing the terminal no longer stops Espanso. espanso.cmd is not used any more,
    which also saves about half a second per Espanso call.

Documentation

  • Troubleshooting: slow start on Windows, with bytecode, an antivirus exclusion or a Dev
    Drive for uv's folders (UV_TOOL_DIR, UV_PYTHON_INSTALL_DIR) (#223, #216).
  • Usage: the rule for which triggers a deploy turns on, and what a local trigger needs (#220).
  • Install: why prompt-workflow is installed next to promptmend, and that it goes in 1.0.0
    ("Update", "Uninstall"; #221).
  • Troubleshooting: doctor's daily update check (update-check.json,
    PROMPT_UPDATE_CHECK=false) and its local server check (#222).
  • Install: "Espanso on Windows": open Espanso once from the Start menu and accept its PATH
    and autostart offer, close every Windows Terminal window before the first promptmend
    command, and where a portable Espanso keeps its configuration (#218).
  • Troubleshooting: on Windows, promptmend or espanso not recognized right after an
    install, and two Espanso instances after installing next to a portable copy (#218).
  • Usage: the trigger list gives each trigger's key and whether the draft leaves the machine,
    and links the data-protection gate and -iok-; "The -if- form" lists the shipped models
    and how model@endpoint sets the endpoint pin (#219).
  • Neutral wording: -risk- is described as a risk-analysis scaffold, and the gate's ID
    check as national ID numbers (Vietnamese formats only today); the match files and patterns
    are unchanged (#219).

v0.22.0

Choose a tag to compare

@github-actions github-actions released this 07 Oct 10:09
Immutable release. Only release title and notes can be modified.
2c5c3b2

Added

  • A portable Windows build (#185): each GitHub Release now carries
    promptmend-<version>-windows-x64.zip, the CLI frozen with PyInstaller (a folder with
    promptmend.exe and its _internal folder, its own Python included), attested like the
    other release files. It is the base of the coming WinGet package vlastimilbures.PromptMend;
    until that is published it is a preview (unsigned). See docs/install.md, "Portable zip".
  • doctor knows the winget install channel (the WinGet Links alias, else the package
    folder, neither holding the version, so the match files survive winget upgrade) and names
    winget upgrade vlastimilbures.PromptMend when a newer release exists. Its cli check data
    gains frozen. A frozen exe still in a temporary or versioned folder (straight from the
    zip or Downloads\promptmend-<version>-windows-x64) is refused as a launcher, with a hint
    to move it to a fixed place such as %LOCALAPPDATA%\Programs\promptmend.

Changed

  • In the frozen build, the interface's command line, promptmend shell and the setup check run
    the exe itself instead of python -m promptmend.cli, and the interface's import check says
    it does not apply.
  • WinGet manifests for the coming package vlastimilbures.PromptMend (#185) are prepared:
    CI validates them and installs the Windows zip through winget on every pull request. The
    package is not on WinGet yet.

v0.21.0

Choose a tag to compare

@github-actions github-actions released this 07 Oct 07:46
Immutable release. Only release title and notes can be modified.
59d6bdb

Added

  • promptmend shell (#183): a plain command line for the terminal with the completion and
    live help of the interface's command line (Tab completes, the bar below explains the line).
    Enter runs the command in the same terminal, so espanso deploy, config migrate and
    secrets set NAME ask there as usual. improve, persona and shell are refused. A
    line that holds a key or gives a key's value is never run, and Enter replaces it on screen
    with <value withheld>; the history (memory only) keeps only lines that ran. It needs a
    terminal (exit 3 otherwise). New dependency: prompt_toolkit, loaded only by shell. See
    docs/commands.md, "shell".
  • An update check (#197): promptmend doctor and a new first Home row, Version, say
    whether a newer release exists (0.22.0 available); doctor and the About screen give the
    update command for your install channel (for example
    brew update && brew upgrade promptmend). It is information only: doctor never warns about
    it, and Home stays "Ready". It asks pypi.org once a day, and at most once an hour after a
    failure (cached in update-check.json in the data folder), within 3 seconds, never from a
    trigger; pypi.org sees your IP address and a User-Agent naming PromptMend. New setting
    PROMPT_UPDATE_CHECK (default true); false, a value it rejects or a settings file it
    cannot read makes no request. doctor --json adds
    latest, update_available and checked_at to the version check. See docs/privacy.md,
    "Update check".

Changed

  • The interface's tab 2 Providers is now 2 Settings (#199): every setting and both API
    keys in one keyboard list, grouped (Output, Keys, Privacy, Models, History, Interface), each
    with a dot (a green ● for a switch on, a key set or a value that is not the default; a
    grey ○ otherwise), its value and the file it comes from. Up/Down (or j/k) move, Space
    switches a true/false setting, Enter picks from a list or edits the value (checked as the
    CLI reads it, in the dialog), r resets it (config unset), / filters. On a key's row,
    Enter and r open the Set key and Remove key dialogs. The persona shows only as
    <set, hidden>. Each change logs its promptmend config set|unset … command on Home. The
    "Change setting", "Set key" and "Remove key" buttons are gone; the provider overview and
    the PROMPT_LOCAL_ONLY sentence moved to the Diagnostics tab. Home's Output row now names
    the tab that switches it, so paste or clipboard output is one Enter away (#198). See
    docs/interface.md, "Settings tab".
  • The interface's command line also refuses config set|get|unset with a key's name and a
    value, or config set with a key-like value, before the value reaches a child's argv.
  • A value your PROMPT_EXTRA_PATTERNS match now counts as a key wherever a command checks
    for one: config set refuses it, config get and config show do not print it, and the
    command lines of the interface and promptmend shell withhold it. The pattern setting
    itself is never hidden by its own patterns.

Fixed

  • The usage history uses SQLite's WAL journal only on SQLite 3.51.3 or later (#196). Before
    3.51.3, WAL could rarely reset a database, and the SQLite bundled with uv's and Homebrew's
    Pythons is older, so the history now keeps the rollback journal there and switches an
    existing WAL database back on its next recorded run. promptmend doctor's sqlite check
    is OK on such a SQLite ("SQLite 3.50.4, rollback journal") instead of warning on every
    install, so Home says "Ready"; it warns only while a database is still in WAL on an old
    SQLite, and an unreadable version is INFO. The check's data gains journal_mode, and the
    interface's Diagnostics tab shows it.

Documentation

  • README is simpler (#200): no ASCII logo, a flow diagram (docs/flow.mmd, rendered into a
    light and a dark SVG by scripts/render_diagram.py) instead of the text one, one-sentence
    highlights, only the Home screenshot, the example collapsed, and one install command per OS.
    The channel and update/uninstall tables are in docs/install.md, whose "Update" section now
    also has the Windows redeploy note for upgrades from 0.20.0 or earlier (#18).
  • The benchmark figures behind CONTRIBUTING's "Known gaps in the default prompt" moved to
    docs/benchmark.md ("Per-draft findings of the 2026-10 round"), its only home; the gaps link
    there. Gap 10 now says the v0.19.0 prompt copies a short pasted email on flash-lite.

v0.20.1

Choose a tag to compare

@github-actions github-actions released this 07 Oct 01:28
Immutable release. Only release title and notes can be modified.
dede6cf

Fixed

  • Windows: every trigger that runs the CLI (-i-, -iok-, -ip-, -if-, -il-, -ilm-,
    -ic- and -p-) failed under Espanso and pasted [Espanso]: An error occurred during rendering (#18). Espanso runs a type: shell var through PowerShell on Windows, which
    cannot run a quoted path followed by arguments. The match files now call the CLI from
    type: script vars: Espanso starts the CLI directly with an argument list, no shell, on
    every system. After upgrading, run promptmend espanso deploy to replace the deployed
    match files (it recognises the old ones as its own). A trigger of your own copied from an
    older deployed file keeps the shell shape: rewrite it as shown in docs/usage.md, "Your own
    triggers".
  • improve and persona print nothing on stderr, not even a Python warning or a library's
    message (they discard it), since a script var treats any stderr output as a failed
    expansion. A crash still exits nonzero, so Espanso still reports it. The promptmend and prompt-workflow
    commands now start through promptmend.entry:main.
  • promptmend espanso deploy no longer refuses a CLI path holding $, a backtick or (on
    Windows) % ^ & | < >, which no shell reads any more. It still refuses a quote, a
    backslash, a control character, and what Espanso itself would replace in the path: {{
    (its variables) and %HOME%, %CONFIG% and %PACKAGES%.

Documentation

  • The Homebrew install adds brew tap and brew trust --formula: recent Homebrew refuses
    to load a formula from an untrusted third-party tap.

v0.20.0

Choose a tag to compare

@github-actions github-actions released this 06 Oct 23:50
Immutable release. Only release title and notes can be modified.
b006b6a

Added

  • The interface's Home tab has a command line (#111): press c from any tab and type a
    promptmend command. It completes commands, options, setting names (after config set,
    get and unset; never a key name there), key names (only after secrets set and
    secrets remove) and profile names, and shows the command's usage and help as you type, or
    the usage error the CLI would print. Up and Down go back through this session's lines;
    Escape leaves it. A line that looks like it holds a key is never shown back or kept in that
    history. The footer shows c Command.
  • Enter on that command line acts on the command (#111). A command that reads, previews,
    changes a setting or writes an export, asking nothing (doctor, config show|get|set|unset|validate, secrets status, profiles list,
    stats, espanso status, history export, any --dry-run, --help or --version) runs
    in a separate process, one at a time, with no input and at most 120 seconds; its output
    (keys redacted) and exit code appear below the line, and Home's session log lists it.
    doctor skips the clipboard there unless you pass --clipboard. espanso deploy,
    espanso detach, config migrate, secrets set NAME, secrets remove, history prune
    and history reset open their tab's dialog, which asks first as the buttons do
    (--yes and the like are ignored). setup, config rollback, config retire and
    profiles migrate say to run them in a terminal; improve, persona and ui are
    refused. secrets set with a value (or --stdin) after the key's name is cleared, not
    run or kept.
  • Home has two more buttons (#111). Recipes… lists the commands Home suggests before you
    have done anything; picking one puts it on the command line, ready to edit, and runs
    nothing until Enter (secrets set OPENROUTER_API_KEY only fills in the key's name: Enter
    then opens the hidden key dialog). Copy last sends this session's latest command, exactly
    as Home's session log shows it (withheld values such as <value withheld> and placeholders
    included), to the terminal's clipboard (OSC 52; a terminal may need it allowed, or drop
    it); it is disabled until there is one, and the interface never reads the clipboard.
  • The interface has a seventh tab, Try (#111, key 7): type a draft, pick Local stub or Real
    provider, the provider, profile ("as configured" by default, as a trigger) and tier, and
    press Run to see the rewrite a trigger would paste. It never reads or writes the clipboard
    and runs in process, so the draft never goes into a command line. It reads the settings as
    a trigger does (an invalid one stops it with the marker), every run goes through the
    data-protection gate (a stub run exactly as its real call would), and a blocked draft
    shows the trigger's marker with nothing sent. Local stub (the default) answers on
    127.0.0.1 with a placeholder key, calls no provider and records nothing. Real provider asks
    first (provider, model, base URL) and is recorded in the usage history as a direct call;
    Home's session log shows it as
    promptmend improve --provider openrouter --source argument --text '<draft withheld>'
    (with its profile and tier too). A line under the result gives the time, requests, tokens and the cost as
    reported, unknown or not applicable, never 0 for a cost nobody reported. The command
    line's refusal of improve now points at the Try tab, and the set-up smoke test's stub
    replies report token counts.
  • OLLAMA_NUM_CTX sets Ollama's context window (options.num_ctx); empty (the default)
    sends nothing (#168).
  • Windows: a one-command install (#186). Each GitHub Release now attaches install.ps1, with
    its version filled in; powershell -ExecutionPolicy ByPass -c "irm https://github.com/vlastimilbures/promptmend/releases/latest/download/install.ps1 | iex"
    installs uv if it is missing (winget, else uv's official installer), then the attested
    wheel and constraints.txt attached to that same Release, runs uv tool update-shell
    and promptmend doctor --no-clipboard, and prints promptmend setup and
    promptmend espanso deploy as the next steps without running them. It prints every
    command it runs; running it again updates in place. PROMPTMEND_VERSION picks another
    release (0.19.0 or later). CI runs it on Windows against the wheel it built, once with no uv
    on PATH, and dry-runs a rendered copy.

Changed

  • The interface's second tab is now labelled "2 Providers" (it was "Providers & keys"), so
    all seven tabs fit on an 80-column terminal. It still holds the keys.
  • The interface's intro and About screen show the new PromptMend logo (a mended speech bubble
    beside the name), the same one that opens the README.

Documentation

  • The README is rewritten as a short landing page: what PromptMend does, screenshots of the
    Home and Try tabs, an example, install paths for macOS (Homebrew, uv), Windows (the
    one-command install, uv) and Linux, a quick start, the triggers and the key commands. It
    renders on PyPI too (absolute links, no GitHub-only syntax).
  • The details moved to pages in docs/: install (verify, update, switch channel, uninstall,
    upgrading from older versions), usage, commands (options, scripting contract, exit codes),
    configuration (the complete settings reference), profiles, privacy, interface and
    troubleshooting. docs/benchmark.md opens with the current results at a glance, the only
    place the numbers are kept, which removes the README's contradicting figures.
  • The package metadata names the project, its keywords and classifiers, and links the docs,
    issues and source on PyPI. The bug report form asks for the install channel,
    promptmend --version and promptmend doctor --json.

v0.19.0

Choose a tag to compare

@github-actions github-actions released this 06 Oct 07:08
Immutable release. Only release title and notes can be modified.
70d5f63

Breaking

  • The project is renamed PromptMend (#169): the package (PyPI and wheel) is promptmend
    instead of espanso-prompt-rewriter, the command is promptmend instead of
    prompt-workflow, and the Python package is promptmend instead of prompt_workflow.
    prompt-workflow stays installed as a deprecated alias until 1.0.0: the triggers,
    --help and --version behave exactly as with promptmend, and every other command
    (and the interface) first prints one stderr line, "prompt-workflow is deprecated; use
    promptmend (removed in 1.0.0)". Usage lines name promptmend either way, and the
    interface's header, intro and About show PromptMend.
  • The marker the triggers paste for an error or a note is [promptmend: …] (was
    [prompt-workflow: …]): a script that looks for the old prefix must look for the new one.
  • The match labels in Espanso's search bar start with PromptMend: (was prompt-workflow:),
    and a deployed file's stamp is # promptmend <version> (managed; edit at your own risk).
    A file an earlier release deployed, with its # prompt-workflow stamp and prompt-workflow
    launcher, still counts as ours (stale), so the next deploy replaces it without a
    conflict. A side-by-side copy is now <name>.promptmend-new. The __PROMPT_WORKFLOW__
    placeholder in the packaged match files is unchanged.
  • OpenRouter calls carry X-Title: promptmend (was espanso-prompt-rewriter; the benchmark
    sends promptmend-bench), so the dashboard lists them under the new name.
  • Upgrade: first uv tool uninstall espanso-prompt-rewriter (the triggers stop until the
    deploy), then uv tool install promptmend==<version> -c <the release's constraints.txt>,
    promptmend espanso deploy and promptmend doctor. The old tool must go first: both
    install a prompt-workflow launcher, so uv refuses promptmend next to it, and after a
    --force install, uninstalling the old tool later deletes the alias. If you already used
    --force, run uv tool uninstall espanso-prompt-rewriter, then install promptmend again
    with --force. scripts/install_macos.sh and install_windows.ps1 uninstall
    espanso-prompt-rewriter themselves (one line says so) before installing. doctor warns while the deployed
    matches still call a prompt-workflow launcher, and its previous-install check, setup and
    profiles migrate still find a checkout from before the rename (its old project name,
    src/prompt_workflow/prompts, a .venv/bin/prompt-workflow launcher or uv receipt).
  • The repository moved to https://github.com/vlastimilbures/promptmend (#169). GitHub
    redirects the old espanso-prompt-rewriter URLs, but update bookmarks and remotes
    (git remote set-url origin https://github.com/vlastimilbures/promptmend.git). The PyPI
    project is promptmend, and the Homebrew formula is promptmend
    (brew install vlastimilbures/tap/promptmend).

Added

  • promptmend doctor has a folders check (#169): it warns while an old
    prompt-workflow folder is still in use, or holds entries left behind because the new
    folder has its own.

  • OPENROUTER_DATA_COLLECTION (allow or deny, empty by default) sets OpenRouter's
    provider.data_collection routing field on every OpenRouter call, both tiers (#29). deny
    routes only to endpoints that do not store or train on requests; empty, the default, leaves
    the request body unchanged. The default google-ai-studio/flex pin served a deny call
    when checked; if a pinned endpoint does not qualify, OpenRouter falls back to one that does
    while OPENROUTER_ALLOW_FALLBACKS=true, and otherwise the trigger pastes an HTTP error
    marker. README "What is sent, and to whom" and the Configuration table describe it.

  • The release workflow can upload each release's sdist and wheel to PyPI as
    promptmend, by trusted publishing (no stored token), once the owner turns it
    on with the repository variable PYPI_PUBLISH (#95). The new pypi job runs after the
    GitHub Release is published, holds only the OIDC token, and uploads the files the release
    job attested, never a rebuild.

  • scripts/brew_formula.py writes the Homebrew formula for the project's own tap
    (vlastimilbures/homebrew-tap, formula promptmend) from uv.lock: the Release's
    sdist plus one resource per runtime dependency, each pinned by SHA-256 (#95).

  • README "Install", "Updating" and "Uninstall" cover each channel: uv from PyPI or from a
    GitHub Release, and Homebrew (the PyPI and Homebrew channels start with 0.19.0), with the
    tap trust note and how to switch channels (#96). Scoop and WinGet are no longer planned.

  • promptmend espanso status and the interface's Triggers tab also list every other
    .yml/.yaml file in Espanso's match/ folder, such as Espanso's own base.yml or your
    own variants, as yours: not managed, never touched by deploy or detach (#38). Our
    backups, side-by-side copies and subfolders such as packages/ are not listed; a symlinked
    file is listed and marked as a link. These lines never change the exit code.

  • Clipboard output: with PROMPT_OUTPUT=clipboard (promptmend config set PROMPT_OUTPUT clipboard, or the interface) the improve triggers put the rewrite on the clipboard and paste
    nothing, so the trigger just vanishes and you paste when ready; switching windows during a
    long wait no longer sends the paste elsewhere. Error markers, the -iok- "sent despite" note
    and the cut-off note still paste; if the clipboard cannot be written, the rewrite is pasted
    after a marker. improve --output paste|clipboard overrides the setting for one call. README
    "Clipboard output" (#134, #23).

  • The interface opens with a short intro: an ASCII wordmark (text only on a terminal of 70
    columns or fewer), the name, version and a tagline (#112). It closes after 0.8 s or on any
    key or click, and that key does nothing else. promptmend ui --no-intro, or the new
    setting PROMPT_UI_INTRO=false (default true; the triggers ignore it), skips it. When an
    earlier checkout install is found, its screen opens once the intro has closed.

  • a in the interface opens an About screen: version, install channel, Python and Textual
    versions, the settings and history folders, licence and repository (#112).

  • The interface teaches its headless commands (#111). Each button's tooltip shows the command
    that does the same in a terminal; each result of a change starts with the command it was
    ($ promptmend config set PROMPT_TIMEOUT_SECONDS 45, a value that looks like a key
    shown as <value withheld>); and Home lists this session's commands, or six recipes such
    as promptmend espanso status --diff before there are any. A test parses every one
    of these commands against the CLI.

Fixed

  • promptmend espanso deploy finds Homebrew's stable bin/ launcher also when Python
    reports the formula's virtualenv through Homebrew's opt/<formula> link rather than its
    Cellar path; before, it fell back to the running script, labelled script instead of
    homebrew (#95).
  • Interface: the header puts the status (ok, 1 problem, 2 warnings) before "set up and
    manage", so a narrow terminal cuts the tagline instead of the status (#174).
  • Interface: the Diagnostics settings table and the Providers & keys key table show a file
    under your home folder as ~/… (in "From", "Also set in" and the "overrides …" and
    "invalid value in …" notes), so the column keeps the file name; config show still prints
    the full path (#174).
  • Interface: Home's headline no longer shows a check's Markdown backticks around a command
    (#174).

Changed

  • The user folders are named promptmend now (#169): settings in ~/.config/promptmend/
    (%APPDATA%\promptmend\), the usage history and deploy manifest in
    ~/.local/share/promptmend/ (%LOCALAPPDATA%\promptmend\). The first management command
    or the interface (not improve, persona, help, --version, an unknown command or shell
    completion) renames the old prompt-workflow folders and prints one line per folder on
    stderr; until then the triggers keep using the old ones. A config folder holding the .env
    that PROMPTMEND_ENV/PROMPT_WORKFLOW_ENV names, or a symlinked old folder, is not moved
    (doctor says what to do). A rename keeps secrets.toml private; when both folders
    exist only what the new one lacks is moved and nothing is overwritten; migration.json's
    paths follow, so config rollback still works; a move that fails is retried by the next
    command. README "Updating" describes it.
  • PROMPTMEND_ENV names the legacy-mode .env (#169). PROMPT_WORKFLOW_ENV still works as
    its old name; when both are set, PROMPTMEND_ENV wins.
  • Interface: the intro no longer closes by itself after 0.8 s; it stays until you press
    Enter, Escape or any other key, or click, and that key does nothing else (#173). A muted
    line under it says so and names the command that turns it off:
    promptmend config set PROMPT_UI_INTRO false. ui --no-intro still skips it once.
  • README "CLI" documents the [promptmend: …] marker as the stable way for a script to
    tell a failed improve run from a rewrite, since the exit code is always 0 (#32).
  • The default prompt's two examples now open CONTEXT with your PROMPT_PERSONA (a new
    {{PERSONA_OPENING}} token, filled like {{PERSONA_RULE}}; without a persona they read as
    before), so a rewrite no longer drops the persona the rule asks for (#49). On the bench with
    a fictitious persona it opened CONTEXT in 105 of 105 scored runs on both default models
    (before: 100 on flash-lite, 96 on gpt-6-luna).
  • The inputs step no longer contradicts "Execute, but state assumptions up front": it adds
    "if step 1 says execute, state your assumption instead and ask only about a gap that blocks
    the task" (#46). The independent review now reads "Use a separate agent with [domain] domain
    knowledge if you can run one, otherwise r...
Read more

v0.18.0

Choose a tag to compare

@github-actions github-actions released this 06 Oct 00:01
Immutable release. Only release title and notes can be modified.
aba52a7

Security

  • Every repeat in the gate's built-in patterns is now bounded, as the code comment already
    claimed (#36). The JWT pattern's three unbounded segments made a 50,000-character draft of
    eyJ- repeats take about 0.29 s of CPU to scan (and 4.5 s at 200,000 characters); the worst
    50,000-character case found now takes about 0.05 s. A pattern now reads only what it needs
    to know a secret is there: a vendor key's minimum length, a JWT's header and the start of
    its payload (eyJ and 7 more characters; the signature is no longer required), and a
    Bearer token's first 16 characters, one of them a letter, digit or underscore (no word
    boundary required after it). A JWT header longer than 8,192 characters or a private-key
    label longer than 64 counts as a match. So the gate flags what it flagged before, plus a
    JWT without its signature, a very long eyJ… run and a long upper-case -----BEGIN label,
    with three exceptions it no longer flags: a "JWT" whose payload does not start with eyJ
    (real payloads are JSON objects, so they always do), a Bearer token whose first 16
    characters are only dots and hyphens, and more than 256 whitespace characters between
    Bearer and its token. A test checks that no built-in pattern has an unbounded repeat.
  • An invalid PROMPT_EXTRA_PATTERNS regex (including a repeat count too large for the regex
    engine, or nesting too deep to compile) is now rejected when settings load, naming the
    entry but never the pattern (#36). config validate, config set, doctor and the
    interface report it instead of only the cloud triggers, and every rewrite trigger, local
    ones too, prints a marker until it is fixed (-p- still pastes the persona; before, the
    local triggers ran and the usage history silently dropped each record). README and .env.example now warn against patterns with
    nested quantifiers, which can take exponential time on every draft.
  • An Ollama cloud model is recognised in any letter case and with a pinned digest
    (GPT-OSS:120B-CLOUD, gpt-oss:Cloud, gpt-oss:120b-cloud@sha256:…) (#33). Before, such a
    spelling counted as local: the data-protection gate did not run, PROMPT_LOCAL_ONLY=true did
    not refuse it, the interface's Providers tab showed it as local and the usage history
    recorded its cost as not_applicable. Only the tag counts, so a name such as
    cloudy-llama:7b stays local.
  • An error that quotes a rejected value no longer repeats one that matches your
    PROMPT_EXTRA_PATTERNS (#32): for example PROMPT_PROVIDER=PRJ-12345 with the pattern
    PRJ-\d+ now pastes Unknown provider <redacted, 9 chars>, and a bad
    PROMPT_TIMEOUT_SECONDS matching a pattern is described in the marker and in
    config validate. config show still shows the
    patterns themselves.
  • --tier with an unknown value is quoted like every other rejected value (#32), so a
    key-shaped one is described instead of pasted back.

Added

  • config validate, doctor and the interface's Home and Diagnostics tabs now scan
    PROMPT_PERSONA with the data-protection gate's patterns (the built-in ones and
    PROMPT_EXTRA_PATTERNS) once (#29). The persona goes with every cloud call in the system
    prompt and the gate never scans it, so a match is now reported by finding name only, never
    the text: config validate lists it as a problem (exit 4) and doctor's new persona check
    warns. Nothing changes on the triggers. A persona that is never sent is not flagged: when
    neither PROMPT_PROFILE nor PROMPT_PRO_PROFILE uses {{PERSONA_RULE}} (e.g. general),
    or with PROMPT_LOCAL_ONLY=true and PROMPT_GATE_LOCAL off. A persona that cannot be read
    shows as such in doctor instead of "not set".
  • PROMPT_GATE_LOCAL (default false) (#33): true runs the data-protection gate for Ollama
    and LM Studio on localhost too, with the same override rules, for a local server that
    relays to a cloud API (LiteLLM, an SSH tunnel). PROMPT_LOCAL_ONLY still allows them. A
    draft it blocks pastes [prompt-workflow: Blocked call to the local server …].
  • The interface's header now shows the installed version next to the name
    (prompt-workflow 0.17.0 — set up and manage) on every screen (#112).
  • OPENROUTER_PRO_MAX_TOKENS (default empty) (#31): the output cap for the pro tier (-ip-,
    -if-, --tier pro), whose reasoning counts against it. Empty keeps today's behaviour, the
    pro tier sharing OPENROUTER_MAX_TOKENS (2400) with the standard tier. --max-tokens and
    a max-tokens pick in -if- still win; the popup's default now keeps this setting.

Changed

  • config set and config unset (and the interface's settings and profile forms) warns, naming the findings
    only, when a saved change leaves a PROMPT_PERSONA that the gate's patterns match and that
    the profiles send, as config validate would flag it. The value is still saved (exit 0).
  • With PROMPT_GATE_LOCAL=true, a blocked cloud call no longer suggests a local trigger
    (-il-) or a local model, which the gate would block too. The message without it is
    unchanged.
  • An invalid PROMPT_EXTRA_PATTERNS regex is now named as entry N (custom_N), the name a
    finding of that entry gets (both count the non-empty entries from 1).
  • config show prints (empty) for a setting set to an empty value on purpose (such as
    PROMPT_TEMPERATURE=), instead of a blank; config get still prints the raw value.
  • README Triggers: a tip to use -ip- for a draft that pastes an email or thread, since -i-'s
    faster model often summarises short pasted material instead of copying it (#42).
  • Match files (#38, #23, #41): every match, the commented-out -ic- too, has a label:
    (prompt-workflow: …), so Espanso's search bar names each trigger instead of showing
    {{output}}. The -if- model list now starts with, and defaults to, default, which keeps
    OPENROUTER_PRO_MODEL and its OPENROUTER_PRO_PROVIDER pin, as the comment and README
    already said (with the shipped settings that is the same openai/gpt-6-luna@openai as
    before; with a custom pro model it now follows that model and uses PROMPT_PRO_PROFILE if
    set, where the old fixed default used PROMPT_PROFILE). The -if- timeout list stops at 120 s (180 removed), since Espanso blocks every
    other trigger while a call runs. The -ip- comment quotes the 2026-10-04 bench (about 6 s
    median, 9 s p95) instead of "~5-8 s". Run prompt-workflow espanso deploy to update the
    deployed matches; until then doctor reports them as stale.
  • README and .env.example say that an http:// Ollama or LM Studio base URL on another
    machine sends the draft in clear text over the network (only the cloud providers require
    https://) (#33).
  • README "Privacy and data protection" has a new "What is sent, and to whom" section (#29): the
    system prompt, including your PROMPT_PERSONA, goes with every call and is not scanned by the
    data-protection gate; OpenRouter calls reach OpenRouter and an upstream endpoint (the pinned
    one, or another while OPENROUTER_ALLOW_FALLBACKS is true, the default) and carry an
    X-Title header naming this app; keys travel only as the authentication header. The
    introduction no longer suggests that only the draft is sent.
  • Docs (#41): the README, .env.example and CONTRIBUTING say that on macOS and Linux the config
    folder (config.toml, secrets.toml, .env, profiles/) is $XDG_CONFIG_HOME/prompt-workflow/
    when XDG_CONFIG_HOME is set (Windows always uses %APPDATA%\prompt-workflow\); the pro
    tier's latency is quoted from the 2026-10-04 bench (median 5.6 s, p95 9.2 s) everywhere;
    CONTRIBUTING says CI runs the tests with --cov and a 95 % floor, and its project tree lists
    previous_install.py (a test now checks the tree names every module).
  • README tips (#23, #38): do not type or switch windows while a rewrite runs, since Espanso
    pastes it wherever the focus is when the answer arrives (the usage history write adds up to
    0.25 s, 1 s on the first write); on Linux the clipboard needs xclip, xsel or
    wl-clipboard; select, copy and type -i- to rewrite text in place; with a release wheel,
    put your own trigger variants in a match file of your own, which prompt-workflow espanso deploy never touches, since editing a deployed file stops its updates. The Windows install
    script is now run with -ExecutionPolicy Bypass -File instead of changing the policy.
  • The benchmark's method and result tables moved from README to docs/benchmark.md (#40);
    README keeps a short "Model benchmark" summary (the default models, their pass counts and
    latency) and links there. Each results heading now names the release whose prompt it scored
    (the current table: the prompt of v0.14.0, unchanged since), and the README's
    example output says it came from v0.7.0 on google/gemini-3.5-flash-lite.
  • The bench (scripts/bench_models.py) reports what its pass rates measure (#48). Each check's
    name starts with its kind (struct:, branch: or draft:), and below the unchanged pass
    column the report gives each kind's pass rate, over the runs scored on it, and the overall
    one with a Wilson 95% interval. Two new checks: the configured persona must be in CONTEXT
    unless the draft states its own role (not scored on a --persona none run; #49), and an
    INPUTS or OUTPUTS that opens with "None" must not then ask for something with
    [REVIEW: …]. kept no longer counts a key found only in INPUTS, unless the draft pastes
    material. So pass counts and kept from earlier runs are not directly comparable with new
    ones (docs/benchmark.md). The bench's note on the drafts once held out now says they are no
    longer held out, and the benchmark notes say the blind pairwise judgement of 0.11.0 was a
    one-off by hand whose harness is not in the repository.
  • A .env that is not UTF-8 (UTF-16, say) is now a marker on the triggers,
    `[prompt-workflow...
Read more

v0.17.0

Choose a tag to compare

@github-actions github-actions released this 05 Oct 15:05
Immutable release. Only release title and notes can be modified.
9fe6912

Upgrading from the install scripts (an editable checkout install) to the release wheel: you no
longer need to migrate from the old install first. Install the wheel, then run
prompt-workflow setup (or open the interface): it finds the checkout, copies its settings,
key and edited profiles with your consent, and deploys the match files. If it finds nothing,
name the checkout: prompt-workflow setup --migrate-from PATH. The checkout's .env stays in
place until prompt-workflow config retire --from PATH.

Added

  • prompt-workflow doctor has a new previous_install check (#110). Before any setting is
    saved (no config.toml, no secret store, not in PROMPT_WORKFLOW_ENV mode) it looks for an
    earlier checkout install whose .env a wheel install does not read: the launcher in the
    deployed match files or the deploy manifest (<checkout>/.venv/bin/prompt-workflow, or
    .venv\Scripts\prompt-workflow.exe on Windows) and the uv tool receipt of an editable
    install. It never scans the disk and never reads that .env, and only a folder whose
    pyproject.toml names this project counts. It also warns when the prompt-workflow that
    PATH finds first is not the installed launcher, for example while a checkout's .venv is
    active. doctor --json adds the check with the data gated, roots, signals,
    env_file, retire_pending and shadow.
  • prompt-workflow config migrate --from PATH copies the settings and key of an earlier
    checkout's .env (#110). It fills only the settings still at their default, so nothing you
    use today changes (the others are listed as kept), and it leaves that .env where it is, so
    the old triggers keep working until the match files are deployed again. A .env in use is
    migrated in the same step as before. prompt-workflow config retire --from PATH then moves
    the old .env into the backup; it is refused while a match file still runs that checkout's
    CLI. Both show a preview first, and config rollback undoes either. prompt-workflow setup
    offers the copy (and the checkout's edited profiles) when it finds such a checkout, or the
    one --migrate-from PATH names, and the retire after the deploy step; doctor warns while
    a copied .env is still in place. A broken .env in a checkout setup found by itself is a
    to-do, not a failure, and setup then saves nothing, so the offer stays open.
  • The interface (prompt-workflow ui) opens a "Previous install" checklist once per session
    when it finds such a checkout, or a copied .env still in place (#110): copy the settings
    and key, copy the edited profiles, deploy the match files, then retire the old .env. Each
    step shows its preview in a dialog whose Cancel has the focus and runs the same service as
    its command; keys are named, never shown. "Enter a path…" looks at a checkout you name, and
    "Skip this checkout" stops the offer for it. Home has a "Previous install…" button and the
    previous_install check, and the Profiles tab's "Migrate from checkout" uses the checkout
    found.

Changed

  • prompt-workflow profiles migrate, the interface's profile copy and setup now say how to use
    every copied file named like a built-in profile, not only default.md: it replaces the
    built-in only once PROMPT_PROFILE_OVERRIDES lists it, and the message gives the
    prompt-workflow config set PROMPT_PROFILE_OVERRIDES ... command (keeping the names already
    listed). doctor's profiles warning for such a file gives the same command.
  • When profiles migrate finds nothing to copy, it says what it compared with (the commit the
    branch shares with its upstream, or HEAD without one) and how to compare with an older
    commit (--rev <commit>), since a profile committed on a branch without an upstream counts
    as unchanged.
  • prompt-workflow config rollback after config migrate --from (#110) no longer says "the
    .env is read again" when only the earlier checkout's .env comes back: this install never
    reads it. The preview says so, notes that the match files still call this install, and names
    the way back (that checkout's install script) or config migrate --from to copy again.
  • Setup's to-do lines name what they are about ("copy the settings of PATH", "copy the profiles
    added or edited in PATH"), and its migration preview no longer reads as if the copy ran. The
    interface's "Previous install" screen notes that rollback leaves the match files deployed.