Instructions editor
Where people write what an assistant should always know or do: project instructions, a system prompt with variables to test, and a list of rules with where each applies.
Loading preview…
Install
- 1
Run this command in your Tailwind CSS project. It adds
components/ai/instructions-editor-project.tsxand installs its dependencies.$ npx shadcn@latest add https://gradientdeck.com/ai-components/r/instructions-editor-project.json
Usage & API
Example
import { ProjectInstructions } from "@/components/ai/instructions-editor-project"
<ProjectInstructions
value="…"
savedValue="…"
onChange={() => {}}
onSave={() => {}}
onDiscard={() => {}}
/>Props ProjectInstructions
| Prop | Type & description | Required |
|---|---|---|
value | string | Required |
savedValue | stringThe last saved text. The panel is dirty while value differs from it. | Required |
onChange | (value: string) => void | Required |
onSave | () => void | Required |
onDiscard | () => void | Required |
snippets | Snippet[] | Optional |
softLimit | numberSuggested ceiling in tokens. Going over is allowed, just flagged. | Optional |
savedLabel | stringShown when nothing is pending, e.g. "Saved Oct 24". | Optional |
Dependencies
- React
- Tailwind CSS
- motion
- lucide-react
Implementation notes
Project instructions is a section headed Instructions, with the aside Used in every chat in this project. The textarea placeholder asks what every chat in the project should know. Under it, the meter is labelled as length against the suggested limit and prints a percentage. If you pass snippets, they render as Add buttons. Each button's title is the full line it would append, and a line already present cannot be added again. Appended text goes on a new line and the caret moves to the end. Discard calls onDiscard. Save calls onSave only while the text is dirty. The idle status uses savedLabel, which defaults to Saved.
Example
import { SystemPromptEditor } from "@/components/ai/instructions-editor-variables"
<SystemPromptEditor
value="…"
onChange={() => {}}
values={values}
onValuesChange={() => {}}
/>Props SystemPromptEditor
| Prop | Type & description | Required |
|---|---|---|
value | string | Required |
onChange | (value: string) => void | Required |
values | Record<string, string>Test values by variable name. Values for removed variables are kept. | Required |
onValuesChange | (values: Record<string, string>) => void | Required |
defaultPreviewOpen | boolean | Optional |
Dependencies
- React
- Tailwind CSS
- motion
- lucide-react
Implementation notes
System prompt is a two-pane editor. The left pane is a textarea over a mirror, labelled System prompt, so the braces stay highlighted while the caret stays visible. The right pane is labelled Variables. With no names yet, it tells you to wrap a word in double braces. Each name found in order gets a Test value field, with an amber border and an amber dot while the value is blank, and an indigo dot once it has text. Values for names you delete from the prompt are left in the values object. Preview is a disclosure. Its closed row already shows an approximate token count of the text with values filled in. Open, it renders the prompt with substitutions in place, and missing names stay as the raw brace token on an amber background.
Example
import { RulesManager } from "@/components/ai/instructions-editor-rules"
<RulesManager
rules={[]}
onRulesChange={() => {}}
newId={() => {}}
/>Props RulesManager
| Prop | Type & description | Required |
|---|---|---|
rules | Rule[] | Required |
onRulesChange | (rules: Rule[]) => void | Required |
newId | () => stringCalled to make an id for a new rule. | Required |
defaultExpanded | string | null | Optional |
Dependencies
- React
- Tailwind CSS
- motion
- lucide-react
Implementation notes
Rules is a headed list. The subtitle says the rules are added to the agent's context in acme/web, and New rule appends an enabled rule with Always scope, then focuses its name field. A row shows the name, or Untitled rule, a scope tag, and a switch. Expanding a normal rule shows the name, the text (placeholder What should the agent do?), and a scope control: Always, Matching files, When mentioned. Matching files reveals a pattern field. When mentioned prints the at-name to type in a prompt. Delete removes the row and shows an Undo status that clears after a few seconds. Leaving a new rule with an empty name renames it Untitled rule. A rule with a file path shows a lock, the path, the text in a read-only box, and a note to edit that file in the repo root.
Choosing a layout
Use project instructions on a project page, above the list of chats, when one block of text should ride along with every conversation and people need to see that it is saved. Snippets help when the same lines get added often, such as citing a file or refusing to guess a missing number. A snippet that is already in the text is disabled and shows a check. Use the system prompt variant in a prompt workspace, where the author is testing one template against sample values before it is stored. The preview is the point. It shows the prompt the model would actually receive.
Use rules when the instructions are many short constraints rather than one essay, and some of them come from the repo. Matching files is for a glob, defaulting to src/**/*.tsx when that scope is chosen. When mentioned tells the person to type an at-name derived from the rule title. Do not use these editors for the sampling knobs. That is the model settings panel. Do not use them to decide which tools exist. That is the tool picker. These three only edit text, and they only report changes through the callbacks you pass.
How is the token number calculated?
Both the project meter and the system-prompt preview use a rough estimate of about four characters per token. It is not a tokenizer for a particular model. The project meter compares that estimate with softLimit, which defaults to 600, and still lets you save when you are over it.
Can a rule that comes from a file be rewritten here?
No. If the rule has a file path, the row is read-only apart from the on and off switch. The expanded body says the text is read from that file and that the next run picks up edits made in the repo. Delete is only on rules that have no file path.