zed icon indicating copy to clipboard operation
zed copied to clipboard

Make Rules Library plaintext instead of LMDB

Open notpeter opened this issue 5 months ago • 11 comments

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:

  1. No shared state - if I'm using Zed on multiple devices, there's no way to share these prompts across those devices.
  2. 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.
  3. 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-r to get to my desired state. This should easily be configurable according to a ChatML-like Handlebars template that can be overriden by prompt_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

notpeter avatar Jul 09 '25 20:07 notpeter

it'd be great if the conversation history could also be stored in plain text (or at least easily exported)

bertlebee avatar Jul 10 '25 00:07 bertlebee

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")

Image

olejorgenb avatar Jul 10 '25 09:07 olejorgenb

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

  1. Syntax: Does using calcurse's syntax as the foundation for our plaintext Rules Library feel like the right direction?
  2. Node Types: Are the proposed node types (prompt, rule, excluded_rule, timed_event) semantically correct for Zed's needs?
  3. 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.scm for syntax-aware tasks. This would make plain text runnable and could proxy commands to an agent CLI like claude, allowing them to be inspected with the Zed debugger. Or, the zed agentic experience.
  4. 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 avatar Aug 04 '25 07:08 public-rant

@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?

  1. Syntax: Does using calcurse's syntax as the foundation for our plaintext Rules Library feel like the right direction?
  2. 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 avatar Aug 04 '25 12:08 notpeter

@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.

A runnable prompt with applicable rules
A runnable prompt with applicable rules

public-rant avatar Aug 05 '25 22:08 public-rant

Note, thread history has already been migrated from LMDB to sqlite:

  • https://github.com/zed-industries/zed/pull/31741

notpeter avatar Aug 21 '25 22:08 notpeter

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.

Danvil avatar Oct 15 '25 19:10 Danvil

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?

jd-santos avatar Oct 28 '25 01:10 jd-santos

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

bertlebee avatar Oct 28 '25 23:10 bertlebee

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

bertlebee avatar Oct 28 '25 23:10 bertlebee

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

tifandotme avatar Nov 23 '25 06:11 tifandotme