A prompt library for the Mac menu bar

Keep the short prompt.
Generate the long one.

You keep seeds like fix this bug and test. Seedbed feeds each seed, plus the prompting guidance for a target model, to an enhancer, and stores the tailored expansion as a file in git. Press ⌥⌘P anywhere, pick the model, and the long version is on your clipboard.

Free and open source (MIT) · macOS 14 or later · Apple silicon and Intel · Developer ID signed and notarized · updates itself

Plain markdown, in a git repository Copy is a file read: instant, offline No account, no telemetry, no server
Seed fix this bug and test 5 words · prompts/fix-bug-and-test.md
Rendered rendered/claude-opus-5/fix-bug-and-test.md

You have this repository open and can read files, run commands, and execute the test suite.

Fix the bug described below, and cover it with a test.

Reproduce it first: find the failing behavior in the actual code and confirm you can trigger it before changing anything. If you cannot reproduce it, say so and describe what you tried instead of guessing at a fix.

Fix the underlying cause, not the symptom. Keep the change minimal: no refactoring, no extra error handling, and no restructuring of code the bug does not touch.

Add a test that fails against the old code and passes against the fix, written in the style and location of the existing tests for that area.

Done means: the bug is reproduced, the cause is fixed, a regression test exists, and the relevant tests pass. Report in a few sentences…

182 words · built 2026-09-05current · seed and guidance unchanged
SeedThe short version you maintainFive words, or a line with {{PLACEHOLDER}} blanks
GuidanceHow that model wants to be promptedThe vendor's own docs, fetched and cached, plus a note per model
EnhancerAn LLM that writes the long versionDefaults to the claude CLI already on your Mac; any OpenAI-compatible endpoint works
Rendered promptOne file per seed per modelWith provenance: which seed, which guidance, which enhancer, when

01Ahead of time, not at copy time

A good prompt is long, specific and model-shaped.
Writing one every time is why you don't.

So in practice you type the short version and accept a worse answer. Seedbed splits the two jobs: you own the seeds, and the tool owns the expansions. Rendering happens in build, not between ⌘C and ⌘V.

Copy is a file read

The render already exists, so copying is instant, works on a plane, and puts no API call between you and the paste. A bad render is caught before it reaches a worker agent, not after.

One file per seed per model

Editing a seed marks its renders stale; it never overwrites them. Each render records the seed hash, the guidance hash, the enhancer and the date, so build only spends on what moved.

Placeholders survive

A seed like fix {{BUG}} in {{PROJECT}} keeps its blanks through the render. Copying opens a small form, one field per blank, each remembering the values you used before.

Why files and git

Prompts change slowly and need to exist on more than one computer. Git gives sharing, history, backup and conflict resolution with no server, and it works away from your own network. Renders are committed too, so when a vendor's guidance moves, git diff shows exactly how the expansion changed. You review a diff rather than trusting a black box.

  • No dependencies. Standard library only; TOML frontmatter parsed with tomllib. Python 3.11 or newer.
  • Degraded guidance is refused, not absorbed. If a vendor page cannot be read, build stops rather than quietly rendering on less input than it had.
  • Machine-local by design. Copy counts and the values you typed into placeholders stay out of the repository, so two Macs never fight over them.
# illustrative: what a guidance change looks like in review
$ git diff rendered/claude-opus-5/fix-bug-and-test.md
@@ -2,4 +2,4 @@
 seed = "fix-bug-and-test"
 model = "claude-opus-5"
-guide_hash = "9a4c1e0b2d7f"
+guide_hash = "45195e0f127e"
@@ -12,3 +12,3 @@
-Work through the following steps in order, and report each one.
+Done means: the bug is reproduced, the cause is fixed, a regression
+test exists, and the relevant tests pass. Skip the narration.

02Same seed, four targets

Four models, four different prompts.
That difference is the point.

A frontier model degrades when you over-specify; an open-weight model needs numbered steps, an output format and an example. The same five words render as 182 words of outcome-focused prose for one and 698 words of procedure for another. A target is data, not a vendor account: rendering for GPT or Llama never calls OpenAI or Meta.

You have this repository open and can read files, run commands, and execute the test suite.

Fix the bug described below, and cover it with a test.

Reproduce it first: find the failing behavior in the actual code and confirm you can trigger it before changing anything. If you cannot reproduce it, say so and describe what you tried instead of guessing at a fix.

Fix the underlying cause, not the symptom. Keep the change minimal: no refactoring, no extra error handling, and no restructuring of code the bug does not touch.

Add a test that fails against the old code and passes against the fix, written in the style and location of the existing tests for that area. Run the tests covering the affected area, plus the fix's own test.

Done means: the bug is reproduced, the cause is fixed, a regression test exists, and the relevant tests pass. Report in a few sentences: the root cause, the change, the test you added, and the test command with its result. Keep the report brief; skip the step-by-step narration.

Bug:
Registry note
Adaptive thinking is on by default. Over-prescriptive prompts written for older models reduce output quality: say what done looks like, not every step.
Shape
Outcome first. One "done means" sentence. No headings, no example.
Length
Opus 5182
GPT-5.4 mini338
Qwen3-VL 30B472
Llama 3.3 70B698
You are a software engineering agent working in a repository you can read and modify. Fix the bug described below, and add a test that covers it.

Work in this order, and do not skip ahead:

1. **Reproduce first.** Locate the relevant code by searching the repo. Run the failing case, the existing test, the command, or a minimal script you write, and capture the actual output. Do not edit any source file until you have observed the failure yourself.
2. **Diagnose.** Read the surrounding code, not just the failing line. State the root cause in one or two sentences before changing anything.
3. **Fix.** Make the smallest change that addresses the root cause. Match the conventions already in the file.
4. **Test.** Add a regression test in the project's existing test suite and style. It must fail against the original code and pass against your fix: verify this by reverting the fix and running the new test. A test that passes either way proves nothing.
5. **Verify.** Run the new test plus the existing suite for the affected area, and paste the actual command output.

Before each tool call that changes a file or runs a command, say in one line why you are doing it.

You are done when: the failure reproduces before the fix and not after, the new test is confirmed to fail without the fix, the affected suite passes…
Registry note
Cheaper worker tier. Benefits from more explicit acceptance criteria.
Shape
Five numbered steps, each with a stop condition. A "say why before each tool call" rule.
Length
Opus 5182
GPT-5.4 mini338
Qwen3-VL 30B472
Llama 3.3 70B698
You are fixing a bug in a repository you have open. Work through the numbered steps in order. Do not skip a step.

1. Read the bug report at the end of this prompt. Restate the bug in one sentence: what happens now, and what should happen instead. If the report does not say what the expected behaviour is, write down the expected behaviour you inferred and say that you inferred it.

2. Locate the code. Search the repository for the file, function, error message, or symbol named in the bug report. List every file path you opened and why. Do not guess at file contents: read the files.

3. Reproduce the bug BEFORE changing any code. Run the failing command, test, or script and paste the exact output you got. If you cannot reproduce it, stop and report what you ran, what happened instead, and what you would need in order to reproduce it.

4. Find the root cause. State the specific line or lines that cause the wrong behaviour, and explain in two or three sentences why that code produces the observed output. Do not describe the symptom again: name the defect.

5. Write a failing test first. Add a test that fails because of this bug, in the repository's existing test framework and in the directory where its tests already live. Run it. Paste the output showing it fails.

6. Fix the bug. Change only the code needed to fix this defect…
Registry note
Open-weight, served locally. Needs explicit structure rather than trusted judgement, and literal instructions: it is a vision-language model being used for text.
Shape
Numbered steps. "Say that you inferred it." "Do not guess: read the files."
Length
Opus 5182
GPT-5.4 mini338
Qwen3-VL 30B472
Llama 3.3 70B698
You are working in a repository you have full access to: you can read files, run shell commands, and run the test suite. Fix the bug described below. Follow these steps in order. Do not skip a step.

STEP 1: REPRODUCE THE BUG BEFORE CHANGING ANY CODE.
1a. Read the bug report at the end of this prompt.
1b. Locate the relevant files. Use search commands (`grep -rn "<symbol>" .`, `rg "<symbol>"`, `find . -name "<file>"`) to find the code named in the report.
1c. Run the failing case: run the existing test suite, or the specific test, or the exact command from the report.
1d. Paste the real, unedited failure output into your answer. If you cannot reproduce the failure, STOP and report exactly what you ran and what happened instead.

STEP 2: FIND THE ROOT CAUSE.
2a. Read the failing function and the code that calls it.
2b. State, in one or two sentences, the exact line or lines that cause the wrong behaviour and why they are wrong. Name the file and line number.

STEP 3: WRITE A FAILING TEST FIRST.
…

OUTPUT FORMAT: use exactly these six headings, in this order:

## 1. Reproduction
## 2. Root cause
## 3. Failing test
## 4. Fix
## 5. Verification
## 6. Summary

EXAMPLE of the level of detail expected (abbreviated, for shape only):

## 1. Reproduction
`$ pytest tests/test_cart.py::test_total -q`
E   assert 0 == 10.0 …
Registry note
Local and offline. Open-weight models need the most explicit structure: numbered steps, an output format, and an example.
Shape
Lettered sub-steps, a fixed six-heading output schema, and a worked example of what a good answer looks like.
Length
Opus 5182
GPT-5.4 mini338
Qwen3-VL 30B472
Llama 3.3 70B698

Openings of the real renders in the starter library, counted on the prompt body. Claude Sonnet 5 is a fifth registered target; add your own with promptlib model.


03What we measured

Does a tailored prompt beat the raw seed?
It depends on the model, and that is the finding.

The premise was checked before this page was written: four tasks with known right answers, each given to the same model twice, once as the five-word seed and once as that model's render. Criteria were registered before anything ran. Both results are published, including the one that did not support the tool.

claude-opus-5No advantage
0 of 4tasks where the render beat the seed on correctness
t4 withdrawn as evidence. Why

Both conditions found the true mechanism wherever it was findable. The render explained more thoroughly and refused more; the seed delivered more working code. On a strong model, tailoring changed risk posture, not correctness.

If you already pay for a frontier model, the honest advice is: type the short prompt. Seedbed is not going to make it answer better.
qwen3-vl-30bRender won
3 of 4tasks won by the render · 10 of 12 criteria against 6 of 12
t4 withdrawn as evidence. Why

The raw seed produced five confident fabrications on one task and skipped the requested test on both fix tasks. The render invented nothing, named nine things it could not see, wrote real tests both times, and did it in 44% fewer words.

Raw seed
"likely using SHA-256 … the file format is likely YAML-like … the save method would likely…"
Render
"The Render class is declared but not defined in the provided code." Nine times, in different words.
What this does and does not settle. It settles that the enhancer earns its cost where the model needs scaffolding and not where it does not. It is one run per model, scored by one reader against pre-registered criteria, on four tasks. The two Opus fix tasks ran with swift build and swift test refused by the permission system. That falls harder on the render than on the seed, because only the render asks for a test run. Those two tasks have since been re-run with the toolchain permitted: on one the render and the seed tied, and the other turned out to have no defect in the code it supplied, so it is withdrawn as evidence either way. On both models the render went looking for code that was not there, which led to a design change: a seed now declares whether it will be pasted into an agent with a checkout or a chat window with a snippet, and the render is built for that context. The raw outputs, inputs and scoring are on the evidence page, so the scoring can be disagreed with rather than taken on trust.

04Three front ends, one library

Summon it over anything.
Type, pick, paste.

The menu-bar app is a SwiftUI panel that appears over any window on any Space. It shells out to the same Python package the command line and the web page use, so staleness, guidance and the enhancer have exactly one implementation.

Fix this bug and test5×
fix this bug and test
⌘1Opus 5 ⌘2GPT-5.4 mini ⌘3Llama 3.3 70B ⌘4Qwen3-VL 30B
Fix a bug in a project4×
fix {{BUG}} in {{PROJECT}} and add a regression test
Review my diff2×
review my changes before I merge
Explain this code1×
explain what this code does
Write a regression test
write a regression test for this
Copied the Opus 5 version and pasted it⏎ paste · ⇧⏎ copy · ⌘1 to 9 model · ⎋

⌥⌘P anywhere. Type to filter, ⏎ pastes into the app you came from, ⌘1 to ⌘9 picks a model and builds the render first if it has never been made. A stale dot means the seed or the guidance changed since.

The web page · python3 -m promptlib serve --open

Fix this bug and test
fix this bug and test
Claude Opus 5 ▾Copied
Review my diff
review my changes before I merge
Claude Opus 5 ▾

Every seed on a row, a model dropdown beside it. Bound to localhost, for your own library.

$ python3 -m promptlib list fix-bug-and-test · Fix this bug and test claude-opus-5 current (2026-09-05) gpt-5.4-mini current (2026-09-05) llama-3.3-70b current (2026-09-05) qwen3-vl-30b STALE: seed or guidance changed review-my-diff · Review my diff claude-opus-5 current (2026-09-05) $ python3 -m promptlib build # renders only what is stale $ python3 -m promptlib copy fix-bug-and-test --model claude-opus-5 $ python3 -m promptlib match "reviewing a diff before I merge" decided by: semantic → review-my-diff (0.25 on body) Review my diff It is exactly a prompt for reviewing changes before merging.

05Let an agent ask for a prompt

Your agent fetches the prompt it needs,
instead of you copying one across.

The Mac app can run an MCP server. Switch it on in Settings, press Copy configuration, paste that into Claude Code, Cursor or Claude Desktop, and the agent has a library it can search.

find_prompt takes a description, not a name. An agent asking for "something for reviewing a diff before I merge" gets the prompt titled Review my diff. A text match answers most asks on its own in well under a tenth of a second; only when it cannot choose does the ask go to the enhancer to be settled. Every prompt is also exposed through MCP's own prompts/list and prompts/get.

  • find_prompt
  • get_prompt
  • list_prompts
  • list_models
  • build_prompt
  • Loopback only, and a bearer token. Both, not either. Nothing on your network can reach it, and every request must carry the token, which lives in the login Keychain.
  • A second, read-only token can look prompts up but can never call build_prompt, so a client you have not decided to trust cannot spend an LLM call. It is not even shown that tool.
  • Wrong tokens lock out after ten tries, doubling from one minute to fifteen, while a correct token is still always served. A request whose Host or Origin is not this Mac is refused, with the reason in the response.
// Claude Code, mid-task, over MCP → find_prompt { "ask": "something for reviewing a diff before I merge", "model": "claude-opus-5" } ← { "decided_by": "lexical", "confident": true, "matches": [ { "id": "review-my-diff", "title": "Review my diff", "matched_on": "title", "reason": "…" } ], "model": "claude-opus-5", "render_state": "current", "render": "You are reviewing a set of uncommitted or unmerged changes in a repository you have open. Your job is to decide whether these changes are safe to merge…" } // the agent puts the render in its own context and carries on

Seedbed 0.1.32 · universal DMG · signed and notarized · updates itself through Sparkle

Plant it.

Or with Homebrew, from the public repository, which is also the tap:

brew tap anatoliv/seedbed https://github.com/anatoliv/seedbed
brew trust anatoliv/seedbed        # Homebrew 6 and later requires this for third-party taps
brew install --cask seedbed

The app creates your library

Seedbed is a front end and does not carry the prompts. On first launch it clones the public library if no valid checkout exists. This needs internet access and Git. You also need Python 3.11 or newer for tomllib. If automatic setup fails, you can clone the library yourself:

mkdir -p "$HOME/Library/Application Support/Seedbed"
git clone https://github.com/anatoliv/seedbed \
  "$HOME/Library/Application Support/Seedbed/Library"

What it asks for, and what it never sends

Pasting into the app you came from needs the Accessibility permission, which macOS asks for the first time you use it. Without it Seedbed copies to the clipboard and tells you why it did not paste.

Crash reports are off. If you turn them on, they carry the stack trace and the versions, and never a prompt, a render, a value you filled in, or a token. Your home folder path is rewritten to a tilde before anything leaves this Mac. There is no other telemetry, and no account.

  • MIT licence
  • macOS 14 Sonoma or later
  • Apple silicon and Intel
  • Git for setup and Python 3.11 to run
  • CLI and web page work without the app
07If it is useful to you

Free, and staying free.

Seedbed is MIT-licensed and costs nothing. There is no paid tier, no trial and no account, so a tip unlocks nothing: it is a way to say the tool was worth something to you, and that is all it is.

Supporters who ask to be named appear in the app's About page. Reporting a bug or telling me what did not work is worth more than a tip, and costs you less.

06Questions

The questions worth asking first.

Why not paste the short prompt and let the model work it out?+
On a strong model, do exactly that. We measured no correctness gain on Claude Opus 5, and the page above says so. On a cheap or local model the picture is different: the raw seed fabricated details it could not see and skipped the test it was asked for, and the render stopped both. If you run open-weight models and find them unreliable, that is who this is for.
Does targeting GPT or Llama call OpenAI or Meta?+
No. A target is data: a profile saying how to prompt that model, built from the vendor's published guidance. The only thing that calls a model is the enhancer, and you choose it. The default shells out to the claude CLI already on your Mac, so there is no API key and no extra spend. --enhancer anthropic uses the official SDK; --enhancer openai takes any OpenAI-compatible endpoint, including one on your own machine.
What does it cost?+
Nothing to install; the code is MIT. Building a render is one enhancer call, about a minute of wall clock, using whatever backend you configured. Copying costs nothing and works offline, because the render is already a file. build skips anything whose seed and guidance have not changed.
What leaves my Mac?+
Two things, both on your command: fetching a vendor's guidance page when you refresh it, and the enhancer call when you build. The MCP server binds to loopback and cannot be reached from the network. The app checks for updates through a Sparkle feed. Crash reporting is off unless you opt in, and never includes prompt text.
Can I use it without the app?+
Yes. The Python package is the product; the app is a front end to it. python3 -m promptlib gives you list, build, copy, match and the local web page, with no dependencies beyond the standard library. The app adds the global hotkey, pasting into the frontmost window, and the MCP server.
Why files in git and not a database or a sync service?+
Prompts change slowly and need to be on several computers, including ones that were asleep when a change happened. Git already does history, backup, sharing and conflict resolution without a server, and a render is prose, so a diff of it is readable. A database would add a schema, a migration path, and a second way for two machines to disagree.
Who is this for, and who made it?+
One person built it for their own daily use, and the repository is open so you can see exactly what it does. There is no company, no support desk and no roadmap promise. If it is useful to you, the issue tracker is where to say so, and that is also how it will get better.