Make Rules Library plaintext instead of LMDB
Summary
Rules need to be importable on a global/system-wide level. Importing rules should be configurable/automatic. The above can be achieved by initializing the Prompt Store LMDB instance from a set of local files, similar to how prompt_overrides currently works.
Details
Currently these are stored in: ~/.config/zed/prompts/prompts-library-db.0.mdb as a binary LMDB. Ideally they would be in a plaintext format so they can be version controlled. This feature is intentionally narrowly scoped to not include dynamic application of rules (e.g. use these rules for Lua, and these rules for Rust) -- and is just getting them into a human readable/backupable/mergable format.
Simplest possible implementation would be a directory of markdown files.
Enables
- Users can share Rules across multiple devices (e.g. by linking zed's config directory to a shared filesystem)
- Users can version control Rules (e.g. linking zed's config directory to a git repo)
more details
Motivation / Details
The old Prompt Library was quite nice for customizing slash commands in the Assistant Context Editor. One use case of these that was under-appreciated was the ability to copy the system prompts from e.g. Claude.ai or ChatGPT to recreate their personalities in the Zed Assistant.
This Prompt Library had some fundamental limitations:
- No shared state - if I'm using Zed on multiple devices, there's no way to share these prompts across those devices.
- No importable state - similar to the above, there's no way to import prompts in the Prompt Library from files, so syncing prompts across devices had to be done completely manually through the UI. But this leads to other issues, like prompts not being version-controllable.
- Default message: No way to customize the default conversation in the Assistant Context Editor (now called New Text Thread). IMO this is what "default prompt" always misunderstood -- the editor exposes a beautiful ChatML editor, but only allows you to configure the default ChatML conversation very strictly, i.e. forces you to stuff default prompts into the first user message. For the system prompt use case mentioned above, I find myself having to key in
cmd-r cmd-r backspace backspace shift-enter cmd-rto get to my desired state. This should easily be configurable according to a ChatML-like Handlebars template that can be overriden byprompt_overrides.
Now Prompt Library has become Rules Library, but Rules have inherited all of the above limitations!
Discussed in https://github.com/zed-industries/zed/discussions/31458 by @jvmncs
it'd be great if the conversation history could also be stored in plain text (or at least easily exported)
it'd be great if the conversation history could also be stored in plain text (or at least easily exported)
It can already be exported to markdown. Click the document icon ("Open Thread as markdown")
Plaintext Rules Library with Calcurse-inspired Syntax
I've been exploring a tree-sitter based approach for a plaintext Rules Library, using calcurse's syntax as a starting point. This would allow us to store rules and appointments in a human-readable, version-controllable format.
Grammar and Syntax Mapping
The grammar maps calcurse's appointment and todo formats to Zed's Rules Library concepts:
| Calcurse Syntax | Zed Concept | Grammar Node |
|---|---|---|
MM/DD/YYYY [1] Description |
All-day event/prompt | prompt |
[priority] Description |
Active rule | rule |
[-priority] Description |
Completed/excluded | excluded_rule |
date @ time -> date @ time |
Timed appointment | timed_event |
Grammar Implementation
The tree-sitter grammar would look like this:
source_file: ($) => repeat(choice($.rule, $.excluded_rule, $.prompt, $.timed_event)),
// Maps all-day events to prompts
prompt: ($) => seq($.date, " [1] ", $.message),
// Maps todos to active/excluded rules
rule: ($) => seq("[", $.positive_priority, "]", " ", $.description),
excluded_rule: ($) => seq("[", $.negative_priority, "]", " ", $.description),
// Preserves timed events for potential future use
timed_event: ($) => seq($.date, " @ ", $.time, " -> ", $.date, " @ ", $.time, " |", $.message)
Application Layer Filtering
At runtime, we'd filter for the content Zed's Rules Library needs:
// Get active rules and prompts for the Rules Library
const activeContent = nodes.filter(node =>
node.type === 'rule' || node.type === 'prompt'
);
// Archived content is preserved but not used
const archivedContent = nodes.filter(node =>
node.type === 'excluded_rule' || node.type === 'timed_event'
);
This preserves the full context of the original apts and todo files while allowing Zed to use only the active content.
I have a working proof-of-concept of this grammar, and all the core test cases are passing:
? Testing 'tree-sitter tests pass'
prompts:
1. ? All-day event is a prompt
2. ? Multiple all-day events are prompts
3. ? Timed event is classified as timed_event
rules:
4. ? Simple rule item
5. ? Negative priority rule item is classified as excluded
6. ? Excluded rule is classified as excluded
Future Possibilities (Out of Scope?)
The timed_event nodes could potentially be used for:
- Prompt logs: A history of prompts that have been executed
- Chat history: Storing conversations with timestamps
- Event-based rules: Rules that trigger at specific times
However, these are likely out of scope for the initial implementation.
Questions for Maintainers
- Syntax: Does using
calcurse's syntax as the foundation for our plaintext Rules Library feel like the right direction? - Node Types: Are the proposed node types (
prompt,rule,excluded_rule,timed_event) semantically correct for Zed's needs? - Integration: ~~Where would be the best place to integrate this kind of parser within Zed's architecture?~~ The goal is to deliver a Zed extension that uses
runnables.scmfor syntax-aware tasks. This would make plain text runnable and could proxy commands to an agent CLI likeclaude, allowing them to be inspected with the Zed debugger. Or, the zed agentic experience. - Enhancements? How about using UI tools like jira/github-issues with mobile apps and APIs to manage the state, and render the plain text periodically or say, per sprint, in the project?
This approach offers a clear path to a version-controllable, plaintext Rules Library while preserving the rich context of the original calcurse file formats. Keen to hear your thoughts.
@public-rant:
This would allow us to store rules and appointments in a human-readable, version-controllable format.
What are you talking about? Rules and appointments?
- Syntax: Does using calcurse's syntax as the foundation for our plaintext Rules Library feel like the right direction?
- Node Types: Are the proposed node types (prompt, rule, excluded_rule, timed_event) semantically correct for Zed's needs?
No. This does not feel like the right direction at all.
I literally don't have an understanding why you think that this is appropriate for a set of LLM prompts in the Zed Rules library. This reads like LLM slop nonsense that has nothing to do with the issue at hand.
@notpeter
My apologies for the noise in my previous comment. I realize now that it was rushed and not fully thought out, adding unnecessary cognitive load to the discussion. I understand completely why it was flagged, and I will be more mindful going forward.
After reflecting on the issue, I see that I was conflating "prompts" with "rules", with the latter being the correct focus here. The core idea I was trying to articulate might be better framed as a simple question: Could plain-text rules be "applicable"? Perhaps analogous to the concept of a runnable.
No need for a detailed response if this is out of scope. Thank you for your time and for all your work on this project.
PS - I've attached a mockup which captures the UX I was originally hoping to describe. I was definitely getting ahead of myself with the implementation details.
Note, thread history has already been migrated from LMDB to sqlite:
- https://github.com/zed-industries/zed/pull/31741
Storing rules as multiple plain-text files would be great. One folder per git project and one folder for "user" rules applied to all projects.
Well this is an unfortunate place to land after a lot of googling about where the prompt files are stored in my first week of using Zed. I'm sure there are very smart reasons for this to be implemented as a DB, but it's frustrating that there's no support for global prompts to be version controlled.
Am I understanding that there's not even a way to sync Rules between devices?
Am I understanding that there's not even a way to sync Rules between devices?
Sadly, no (or at least there wasn't last time I looked into it). I find it a little amusing that zed is so great at managing shared state through CRDTs between different users at the same time, but that doesn't seem to extend to the same user with multiple installations of zed
To be fair, the state of rules management is a nightmare everywhere, I think I'll create a new standard to unify rules management across the AI space
I think opencode approach is pretty straightforward, it reads ~/.config/opencode/AGENTS.md.
I'd be cool if Zed could support that aswell, good usecase for this would be to have single AGENTS.md and symlink it to wherever it was used by other agents