Prompts and instructions
Crystal is prompt-neutral. Every model-bound string this product
sends is authored here. Operators may replace Work, Plan, Review, the Review
user turn, topic naming, compaction, and image description
by placing files under ~/.crystal/prompts and
<workspace>/.crystal/prompts.
Named files (work.md, plan.md, review.md, review.user.md, topic.md,
compaction.system.md, compaction.user.md, image.system.md, and
image.user.md; .txt is also accepted):
- Within direct overrides, the Home file is applied before the project file.
- A project file replaces the home file for that name.
- Empty files are treated as missing.
- The host never writes prompt files.
Prompt set selection is separate from direct prompt overrides. Reusable sets
live only under ~/.crystal/promptsets/<name>/; the workspace is never scanned
for prompt sets. Each set contains prompt.json and any subset of those
named files (.txt is also accepted).
Missing or empty members use the built-in prompt for that name.
prompt.json may include name and description. name is a display title
of at most 80 characters. description is at most 280 characters. The
directory name remains the id used by commands. enabled turns the directory
on. Omitting enabled means off. Unknown fields are kept. A missing,
unreadable, or invalid file skips that directory. Enable and disable do not
create a directory or a missing file, and they leave a broken file unchanged.
At most one prompt set is enabled. Enabling one turns the others off. If more
than one set is hand-edited to enabled: true, Crystal uses the built-in
prompts and reports the conflict. /promptset default turns every set off.
Final precedence for each named prompt:
- Built-in default.
- Selected Home prompt set.
- Direct
~/.crystal/promptsoverride. - Direct
<workspace>/.crystal/promptsoverride.
Use /promptset (alias /prompts) to list available sets and the effective
source of Work, Plan, and Review. /promptset <name> enables that set.
/promptset default returns to the virtual built-in selection. Switching is
refused while a turn runs, though listing remains available. A non-default
set appears as Prompt <name> in the status bar and as a startup note.
crystal promptsets list|show|enable|disable edits the same files outside a
session.
Older promptSet and promptAttachments values in config.json are ignored.
The next preference save omits them. There is no migration tool. Add
prompt.json to each directory you still want.
Prompt attachments append after the resolved Work, Plan, or Review text.
An attachment does not replace topic, Review user, compaction, or image
description. Each attachment is a directory
with prompt.json and any of work.md, plan.md, and review.md (.txt
is also accepted). A mode with no file gets nothing from that attachment.
Empty files are treated as missing. A trailing newline at the end of an
attachment file is kept. Directory names are 1-64 lowercase
alphanumeric words joined by single hyphens. default is allowed.
Attachments are discovered in both places:
~/.crystal/prompt-attachments/<name>/<workspace>/.crystal/prompt-attachments/<name>/
The workspace scan is the current workspace root only. Parent directories are
not walked. When the same name exists in both places, the workspace
prompt.json replaces the Home file, including enabled and order.
Discovery does not enable a directory by itself.
Many attachments may be enabled. They append in order, then by directory
name. A missing order sorts last. Enabling a name places it last and
rewrites the enabled orders as 0, 1, 2, and so on. Disabling sets
enabled to false and does not renumber. Placeholders inside an attachment
expand with the same values as the body.
/promptattach lists every discovered attachment. Effective rows are numbered
and show the display name, description, and Home or Workspace source.
/promptattach enable <name> and disable <name> edit the winning directory.
/promptattach up <name> and down <name> move a name in the enabled order.
Changes are refused while a turn is running. Listing stays available. The
status bar still shows only the selected prompt set. crystal prompt-attachments list|show|enable|disable accepts --home, --workspace,
--source home|project, and --format text.
crystal, crystal space, and crystal run follow the enabled manifests.
--prompt-set <name> forces one
set for that process, including a set whose file says enabled: false.
default forces the built-in text. --prompt-attachments off appends
nothing and refuses /promptattach enable, disable, up, and down. Listing
stays available. Omitting the flag, or passing on, follows the files.
Repeat --prompt-attachment <name> to append that attachment after the
enabled set, even when its prompt.json says enabled: false. A name that
is already enabled stays in its file order. The same flag with
--prompt-attachments off is rejected, and a name that is not in Home or
the launch workspace fails startup. /promptattach enable, disable,
up, and down are refused for a forced name and do not write the file.
Other names can still be changed. Listing stays available. A later workspace
change that no longer contains a forced name skips it and prints a note.
--prompt-set refuses /promptset switching for the process, including
default, and does not write prompt.json. Listing and export stay
available. None of these flags write prompt.json or config.json.
Enabled attachment text is added after the body is bound, and before an ordinary plugin prompt hook appends its own text.
The built-in Work and Plan assistant name is Crystal Code. Work, Plan,
Review, compaction, and image-description templates use host-owned placeholders ({{name}}).
Composite session slots are {{env}}, {{skills}}, {{directories}}, and
{{instructions_section}} or raw {{instructions}}. Atomic session slots
include {{workspace}}, {{is_git_repo}}, {{git_root}}, {{platform}},
{{os}}, {{architecture}}, {{date}}, {{time}}, {{provider}},
{{model}}, {{model_line}}, {{mode}}, {{product_name}},
{{session_id}}, and {{approval}}. {{os}} is the operating system name
and version. {{architecture}} is the process architecture, such as x64
or arm64. {{time}} is the local time with a numeric offset, captured
when that system message is composed. {{is_git_repo}} is yes when the
workspace directory itself contains a .git directory or file.
{{git_root}} is the repository root found by walking parent directories,
or empty when that walk finds none. {{session_id}} is the saved session
id. {{approval}} is the approval mode (plan, default, edit,
review, audit, or full). {{mode}} is plan or work for Work and
Plan, review for Review system text, compaction for compaction
system text, and image for image-description system text. The {{env}} block includes the operating system,
architecture, and local time, and adds git root, session, and approval
lines when the host has them. {{directories}} is empty when the session
has no added directory rules. Otherwise it is the same session directory
access text appended to workspace instructions. Built-in templates do not
declare this slot. It refreshes when the live system message is replaced,
including after /access. These values refresh
on /cd, /model, /approval, and whenever the live system message is
replaced. Review user templates add {{conversation}},
{{tool_name}}, {{tool_arguments}}, {{host_risk}}, {{host_authority}},
and {{classification_summary}}. Compaction user templates add
{{conversation}}, {{prior_summary_section}}, {{summary_task}},
{{output_template}}, and {{todos_section}}. Image user templates add
{{question}}, the description request or the model’s question.
Placeholder names are
case-insensitive. Unknown names are left unchanged. A plugin may add
further names. While resolving a name, the plugin can read the current
session model and whether review is using its own model. The host rejects
a name it already owns, and inserts the plugin’s value as text. Templates must declare
every host slot they need. When Skills is enabled, available-skill guidance
fills {{skills}}. Composite host values are not overlayable.
Workspace facts are appended under “Workspace instructions” on Work and Plan only. Review does not receive that instruction block. Enabled prompt attachments can still append to Review.
Instruction sources, in order:
~/.crystal/instructions.md(or.txt)<workspace>/.crystal/instructions.md(or.txt)<workspace>/.crystal.md- OpenCode-compatible rule files (below)
AGENTS.md and CLAUDE.md are extra instructions, not prompt
replacements. They never replace Work, Plan, or Review.
- Global: first existing file among
~/.crystal/AGENTS.md,~/.crystal/CLAUDE.md,~/.config/opencode/AGENTS.md, and~/.claude/CLAUDE.md(XDG_CONFIG_HOMEis honored for the OpenCode path). - Project: walk from the workspace up to the git root. The first
matching name wins (
AGENTS.md, thenCLAUDE.md, thenCONTEXT.md). Every file of that name on the walk is appended.CLAUDE.mdis used only when noAGENTS.mdexists on the walk.
ruleFiles in config.json turns those compatible files on or off.
global and project each default to on and are omitted until off.
/rules shows them and writes the same file. /rules on or off sets
both sides. /rules global off or /rules project off sets one side
and leaves the other as it is, including a launch override that is not
on disk. --rules does the same for one process and is not written.
off skips that discovery. instructions.md and .crystal.md stay.