Prompt Optimizer takes a rough prompt and has a model rewrite it: clearer instructions, explicit structure, the constraints you forgot to state. It works on system prompts and user prompts, can refine over several rounds, and then runs the original and the optimized version against the same model so you can see whether the rewrite actually helped. An evaluation mode scores a single result or compares two, and an image mode does the same for text-to-image and image-to-image prompts.
It comes in four forms: a hosted web app, a desktop app for Windows, macOS and Linux, a Chrome extension, and a Docker image that also exposes an MCP server for clients such as Claude Desktop. The web version works client-side: settings and saved prompts stay in your browser, and requests go straight to the model provider you configure, on your own key. It supports OpenAI, Gemini, DeepSeek, Grok, Zhipu, SiliconFlow and any OpenAI-compatible endpoint, including a local Ollama.
The project is by the developer linshenkx, is AGPL-3.0 licensed, and has gathered about 36,000 stars since it launched in February 2025. The interface and documentation are in English and Chinese.
- Repository: github.com/linshenkx/prompt-optimizer
- Licence: custom (Other)
- Language: TypeScript. Stars: 36.2K. Forks: 4,182. Last push: Sep 24, 2026.
- Scan: safe, Sep 24, 2026, commit 92c5aaa
Who it is for
People who write prompts for work, from marketers using a chat model to developers building on an API, who want a structured way to improve a prompt and check the improvement rather than tweaking by feel.
Getting started
1. Try the hosted web app first; it needs only a model API key, kept in your browser
open https://prompt.always200.com2. Or run your own copy with Docker, then open http://localhost:8081
docker run -d -p 8081:80 --restart unless-stopped --name prompt-optimizer linshen/prompt-optimizer3. For a private deployment, add a password (and optionally a preset key)
docker run -d -p 8081:80 -e ACCESS_PASSWORD=your_password -e VITE_OPENAI_API_KEY=your_key --restart unless-stopped --name prompt-optimizer linshen/prompt-optimizerDesktop installers are on the GitHub releases page and the extension is in the Chrome Web Store. The desktop app avoids the browser's CORS limits, which matters if you want to reach a local Ollama. The README warns against presetting API keys on a public deployment, because VITE_ variables end up readable in the browser bundle.
Safety scan
We cloned linshenkx/prompt-optimizer at commit 92c5aaa on Sep 24, 2026 and ran the checks described on the GitHub Tools page: credential patterns, decode-and-execute code, install-time scripts, committed binaries, risky CI workflows, every host the code talks to, known vulnerabilities in pinned dependencies, and project hygiene. A person read every hit. This is what we found.
- No suspicious patterns, bare-IP URLs or committed binaries across 1,903 files and about 409,000 lines, mostly TypeScript and Vue.
- Four secret hits, all AWS-format access keys in tests/e2e/fixtures/vcr: recorded image-generation responses whose presigned S3 download links carry a credential ID. The project has already replaced it with the placeholder AKIAXXXXFILESEXAMPLE, so nothing usable is committed.
- No npm install hooks. The one shell script, docker/start-services.sh (41 lines), fills in the nginx config, generates the runtime config.js and starts nginx and the MCP server under supervisord; it fetches nothing.
- pnpm-lock.yaml pins 925 packages with 14 known advisories (7 high, 6 moderate, 1 low): denial-of-service bugs in brace-expansion, which is build tooling, plus http-cache-semantics, fast-uri, ip-address and DOMPurify. None is critical, and the documentation site's 65 packages are clean.
- The host list matches the feature list: about 20 model providers (OpenAI, Anthropic, Gemini, DeepSeek, SiliconFlow, Zhipu, MiniMax, ModelScope and others) and the project's own prompt.always200.com and garden.always200.com. We found no analytics service. Three workflows, none using pull_request_target, with all 10 third-party actions pinned to tags rather than commits. Licence present; no security policy, Dependabot or CodeQL.
What the scanner counted
| Check | Result |
|---|---|
| Secrets | 4 candidates found and read; see the notes above. |
| Suspicious code | None found. |
| Install-time code | 1 installer script |
| Committed binaries | None. |
| CI workflows | 3 workflows. None use pull_request_target. 10 of 10 third-party actions pinned to a tag rather than a commit. |
| Network hosts | 40 distinct hosts referenced from source; most often api.openai.com, prompt.always200.com, garden.local, github.com. No URLs to bare IP addresses. |
| Known vulnerabilities | 14 advisories across 954 pinned packages: 0 critical, 7 high, 6 moderate, 1 low. pnpm-lock.yaml: 925 packages, 14 advisories; site/pnpm-lock.yaml: 65 packages, 0 advisories. |
| Project hygiene | Has licence file. Missing security policy, automated dependency updates, CodeQL, contributing guide. |
| OpenSSF Scorecard | Not scored: the project is not in Scorecard's weekly index. |
The raw findings
Every hit the scanner wrote out, with a link to the exact line at the scanned commit. Secrets candidates are redacted.
Secret candidates (4, redacted)
| Where | Rule | Match |
|---|---|---|
| tests/e2e/fixtures/vcr/test-image-image2image-generate-spec-ts/上传输入图并在对比模式下生成-original-optimized-两张图.json:69 | aws-access-key | AKIAXX…PLE (20 chars) |
| tests/e2e/fixtures/vcr/test-image-image2image-generate-spec-ts/上传输入图并在对比模式下生成-original-optimized-两张图.json:92 | aws-access-key | AKIAXX…PLE (20 chars) |
| tests/e2e/fixtures/vcr/test-image-text2image-generate-spec-ts/切换到-siliconflow-图像模型并生成图片-对比模式.json:79 | aws-access-key | AKIAXX…PLE (20 chars) |
| tests/e2e/fixtures/vcr/test-image-text2image-generate-spec-ts/切换到-siliconflow-图像模型并生成图片-对比模式.json:101 | aws-access-key | AKIAXX…PLE (20 chars) |
Installer scripts (1)
- docker/start-services.sh, 41 lines
Worst known vulnerabilities (14 of 14)
| Advisory | Severity | Package | Summary |
|---|---|---|---|
| GHSA-6j4f-fj2g-mc7p | high | brace-expansion@1.1.18 | brace-expansion: DoS via uncontrolled recursion in parseCommaParts causing stack exhaustion |
| GHSA-qhr7-859c-m2p7 | high | brace-expansion@1.1.18 | brace-expansion: DoS via uncontrolled recursion on nested brace groups causing stack exhaustion |
| GHSA-6j4f-fj2g-mc7p | high | brace-expansion@2.1.4 | brace-expansion: DoS via uncontrolled recursion in parseCommaParts causing stack exhaustion |
| GHSA-qhr7-859c-m2p7 | high | brace-expansion@2.1.4 | brace-expansion: DoS via uncontrolled recursion on nested brace groups causing stack exhaustion |
| GHSA-6j4f-fj2g-mc7p | high | brace-expansion@5.0.9 | brace-expansion: DoS via uncontrolled recursion in parseCommaParts causing stack exhaustion |
| GHSA-qhr7-859c-m2p7 | high | brace-expansion@5.0.9 | brace-expansion: DoS via uncontrolled recursion on nested brace groups causing stack exhaustion |
| GHSA-ch52-4w7c-c8xp | high | http-cache-semantics@4.2.0 | http-cache-semantics max-stale handling can disclose cross-user cached responses |
| GHSA-q2hr-2g5m-vwhr | moderate | brace-expansion@1.1.18 | brace-expansion: Quadratic-time expansion of the `{a},b}` rewrite causes CPU denial of service |
| GHSA-q2hr-2g5m-vwhr | moderate | brace-expansion@2.1.4 | brace-expansion: Quadratic-time expansion of the `{a},b}` rewrite causes CPU denial of service |
| GHSA-q2hr-2g5m-vwhr | moderate | brace-expansion@5.0.9 | brace-expansion: Quadratic-time expansion of the `{a},b}` rewrite causes CPU denial of service |
| GHSA-hrr3-gc8f-f4qj | moderate | fast-uri@3.1.7 | fast-uri vulnerable to inconsistent host case normalization via percent-encoded octets |
| GHSA-h3mg-xc3c-68pw | moderate | ip-address@10.7.0 | ip-address: Address6 builds a parse diagnostic proportional to the input with no length bound, allowing a single long st… |
| GHSA-j6r3-76f7-8jcv | moderate | ip-address@10.7.0 | ip-address: isInSubnet() and isHostInSubnet() compare addresses of different families as if they shared an address space… |
| GHSA-p98j-92pf-mc4p | low | dompurify@3.4.15 | DOMPurify: IN_PLACE: node-removing afterSanitize hook leaves detached subtree event handlers armed, causing DOM XSS |
By the numbers
| Stars | 36.2K |
|---|---|
| Forks | 4,182 |
| Contributors | 32 |
| Commits | 947 |
| Open issues | 7 |
| Open pull requests | 3 |
| Releases | 49 |
| Latest release | v2.11.10 |
| Licence | custom |
| Main language | TypeScript |
| Project age | 1 year |
| Last push | Sep 24, 2026 |
| Tracked files | 1,903 |
| Lines of code | 408.6K |
| Checkout size | 46 MB |
Lines by language: TypeScript 206.1K, Markdown 102.6K, Vue 63.3K, JavaScript 15K, JSON 14.9K, CSS 4,901.
Questions
Is Prompt Optimizer free?
Yes. It is AGPL-3.0 licensed, and the hosted web app, desktop app, extension and Docker image are all free. You pay only the model provider whose key you enter, at its normal rates, or nothing if you point it at a local model through Ollama.
Does Prompt Optimizer see my prompts or API keys?
According to the project, no. The web app and extension process everything client-side: keys and saved prompts are stored in your browser, and requests go directly from your device to the provider you configured rather than through a server run by the project. A self-hosted Docker copy works the same way on your own infrastructure.
Can it optimize image prompts?
Yes. An image mode handles text-to-image, image-to-image and multi-image prompts with models such as Gemini, Seedream and Grok, and shows previews you can download, so you can compare what the original and rewritten prompts actually produce.
This post is part of GitHub Tools, where every repository is cloned and scanned before it is written up. The scan is a snapshot of one commit on one day; the repository has moved on since, so check it before you install.
