Home directory
本頁內容尚未翻譯。
Self-contained release archives are named
CrystalCode-<operating-system>-<architecture>.zip. The supported values
are linux-x64, linux-arm64, macos-arm64, and windows-x64. The platform
installers replace the full platform release contents under binaries/code/.
Developers install the current checkout with scripts/install-local.sh or
scripts/install-local.ps1. Those scripts publish Release into build/
using the release workflow arguments (--self-contained true,
PublishSingleFile=true, and the matching runtime), then replace the full
contents of binaries/code/.
~/.crystal/ binaries/code/CrystalCode (CrystalCode.exe on Windows) config.json providers.json prompt-history.jsonl credentials.json permissions.json trusted.json instructions.md prompts/work.md prompts/plan.md prompts/review.md prompts/review.user.md prompts/topic.md prompts/compaction.system.md prompts/compaction.user.md prompts/image.system.md prompts/image.user.md promptsets/<name>/prompt.json promptsets/<name>/work.md promptsets/<name>/plan.md promptsets/<name>/review.md promptsets/<name>/review.user.md promptsets/<name>/topic.md promptsets/<name>/compaction.system.md promptsets/<name>/compaction.user.md promptsets/<name>/image.system.md promptsets/<name>/image.user.md prompt-attachments/<name>/prompt.json prompt-attachments/<name>/work.md prompt-attachments/<name>/plan.md prompt-attachments/<name>/review.md skill/<name>/SKILL.md skills/<name>/SKILL.md tools/<directory>/tools.json data/tools/<directory>/ plugins/ data/plugins/<directory>/ sessions/<id>.json media/<sha256> logs/ space/config.json stores mutable operator preferences such as the selected provider
and model. workspaceTrust asks before the first interactive entry into a
directory (default on; omitted when on, false when off). A yes is stored
in trusted.json as the git root, or the workspace path when there is no
git repository. That file is not written by the workspace. The operator
space {home}/space is trusted without a prompt and without a ledger
entry. Its trust root is that directory even when a parent is a git
repository, so opening it does not grant the parent. /trust forget does
not remove that trust or a separate parent grant. A child of space
follows the ordinary rule unless space is the git root. crystal space
creates the directory and opens the terminal there. /space switches an
open session to that directory and creates it when it is missing.
/cd with a path and /space are refused while a turn is running.
crystal run --space
uses that directory and creates it when it is missing. It cannot be
combined with --workspace. crystal run
does not read workspaceTrust. --workspace-trust on|off is process-only:
omitted or on denies an untrusted directory before the session exists,
and off skips the check without recording trust. The operator space
passes that check.
For example, an unlimited time budget with finite call limits is:
{ "executionBudget": { "maximumModelCalls": 48, "maximumToolCalls": 96, "maximumDurationSeconds": null }, "bashTimeoutSeconds": "unlimited"}bashTimeoutSeconds is omitted when it is the 600 second default and
backgroundBashTimeoutSeconds when it is the 10800 second default. null and
"unlimited" both mean no timer. The two timers are independent of each other.
providers.json stores the provider catalog as a root object keyed
by provider name, with an array for multiple protocols under one name. The
catalog overlays built-in definitions. When providers.json exists, it takes
precedence over legacy config.json.providers; otherwise the legacy field is
read. Saving preferences copies legacy provider definitions to providers.json
if needed, then preserves the legacy field in config.json so an older running
version can continue reading it. Preference saves do not rewrite an existing
providers.json. An existing providers.json accepts // and /* */
comments and trailing commas (JSONC); the host never rewrites it, so comments
survive. config.json, including its legacy providers field, and every other
JSON file remain strict JSON. Duplicate model ids across protocols under one
provider are rejected. Editing provider definitions in the TUI is deferred
product work. The catalog changes by editing this file, then restarting.
Project overlay (wins over home for named prompts, prompt attachments, Crystal skills, and tool sets of the same directory name):
<workspace>/.crystal/ instructions.md prompts/work.md prompts/plan.md prompts/review.md prompts/review.user.md prompts/topic.md prompts/compaction.system.md prompts/compaction.user.md prompts/image.system.md prompts/image.user.md prompt-attachments/<name>/prompt.json prompt-attachments/<name>/work.md prompt-attachments/<name>/plan.md prompt-attachments/<name>/review.md skill/<name>/SKILL.md skills/<name>/SKILL.md tools/<directory>/tools.json plugins/<directory>/plugin.json data/tools/<directory>/ data/plugins/<directory>/<workspace>/.crystal.mdconfig.json is not part of the project overlay. Operator preferences load
from the Home config.json only; workspace-level configuration is deferred
product work.
Operator plugins and external tool sets keep their own runtime data under a
data/ root, split by kind. The global root is {home}/data; the project root
is <workspace>/.crystal/data. Each extension’s global directory is
{home}/data/{plugins|tools}/<directory> and its project directory is
<workspace>/.crystal/data/{plugins|tools}/<directory>. Both are separate from
the tools/ and plugins/ install trees. The host resolves both paths and
creates the directories when the extension first receives them, at plugin
attach or before a tool call; it never writes secrets there. A
dotnet host tool reads them from ToolHostContext.GlobalDataDirectory and
ToolHostContext.ProjectDataDirectory. An exec child reads them as the
per-process environment variables CRYSTAL_TOOL_DATA (global) and
CRYSTAL_PROJECT_DATA (project). A disk plugin that implements
CrystalCode.Plugins.Data.IPluginDataDirectory receives them through
AttachDataDirectories.
Overlay is built-in default, then ~/.crystal, then the project
.crystal. A selected prompt set sits between the built-in text and the
direct Home files. Named prompt files replace Work, Plan, Review, the Review
user turn, topic naming, compaction, and image description.
Built-in Work and Plan identify the assistant as Crystal Code. Operators who replace those files choose their own identity.
instructions.md and .crystal.md 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. Files may be .md
or .txt. Empty files are treated as missing. The host never writes
prompt files. The host appends a non-overlayable <env> block between
the Work or Plan body and those instructions. When Skills is enabled,
available-skill guidance is appended after the env block.
Skills are OpenCode-compatible SKILL.md folders. They are loaded
on demand through the skill tool. Available-skill guidance lists
name and description only; it does not include absolute paths. When
Skills is enabled, read, list, tree, glob, grep, and search of any path inside a Skills
search directory (skill / skills trees, including files that are
not SKILL.md) auto-execute as workspace reads. The comparison uses
the final target of each symbolic link. Other
outside-workspace reads ask the operator, or go to the Review model
in Review or Audit. They never replace Work, Plan, or Review. config.json field skills
enables or disables the feature
(default true). When false, the tool is omitted and skill guidance
is not appended. Later sources overwrite earlier ones with the same
skill name.
- Global:
~/.claude/skills/<name>/SKILL.md,~/.agents/skills/<name>/SKILL.md,~/.config/opencode/{skill,skills}/<name>/SKILL.md(XDG_CONFIG_HOMEis honored),~/.opencode/{skill,skills}/<name>/SKILL.md, then~/.crystal/{skill,skills}/<name>/SKILL.md. - Project: walk from the workspace up to the git root. At each
directory, scan
.claude/skills,.agents/skills,.opencode/{skill,skills}, and.crystal/{skill,skills}. Crystal paths overwrite OpenCode-compatible paths of the same name.
Each SKILL.md needs YAML frontmatter with name and description.
The skill id is the containing directory name when that name is 1–64
characters of lowercase alphanumerics with single hyphens. Frontmatter
name may be that id or a display title and does not have to match
the directory. If the directory name is not a valid id, a valid
frontmatter name is used instead. Folded (>) and literal (|)
YAML descriptions are accepted.
AGENTS.md and CLAUDE.md are OpenCode-compatible rule files, not
prompt overlays. They are combined into the same instruction block
and 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. - 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.
config.json field ruleFiles is an object with global and project.
Each defaults to on. A missing object or member means on. The object is
omitted when both are on; a written object includes only members that are
off. global false skips the four global candidates. project false skips
the walk. /rules shows the switches, sets both with on or off, or sets
one side with global or project followed by on or off, and writes
config.json. It reloads Work and Plan instructions for the next prompt and
does not change an archived turn. It does not change instructions.md or
.crystal.md. A process --rules value is on, off, or a comma-separated
list of global=on|off and project=on|off. An assignment leaves the other
side as already configured. The flag is not written to config.json. A later
preference save applies only the side that command sets, so a launch
assignment on the other side stays off disk.
credentials.json is the persistent API-key store. Values are plain text,
keyed by provider name, and the file is created with owner-only
permissions. Process environment variables override those file credentials.
Operator tool sets live under tools/. A project directory of the same
name replaces the home set as a whole. tools.json field enabled
(default true) omits a set without deleting it. config.json field
externalTools enables discovery (default true). Each set also gets
runtime-data directories under data/tools/. See
docs/external-tools.md.
An unreadable or invalid project manifest with the same directory name
also hides the home set. timeoutSeconds defaults to 120 for both runners,
independent of bashTimeoutSeconds;
"unlimited" disables the per-call timer while preserving turn and user
cancellation. Exec processes are killed on cancellation or timeout. Dotnet
calls receive a cancellation token and stop waiting on timeout; in-process
code that ignores cancellation cannot be forcibly stopped.
/tools groups the effective host and external catalogs, aligns their Plan and
Work membership, and shows external source, set, author declaration, effective
approval, and catalog totals. It also owns external-tool
configuration: on, off, reload, and independent home / project
author or host policies. Changes are persisted to config.json and reload
the catalogs when required.
/status is the compact diagnostic view. Separate Workspace, Model, Tokens,
and Options cards report operating modes, provider identity, cumulative
provider-reported input/output/total token usage, the latest request’s
proportional context bar, and feature switches. /status full also shows the
effective retry and approvalRetry policies, the latest request token
breakdown, and adds Activity and Tools cards for session identity and start
time, invocation counters, queue and todo counts, and tool-catalog totals. The
persistent chrome remains the smallest live summary.
/status labels cumulative values as session usage and reserves the latest
request breakdown for /status full; its output does not depend on status-line
customization.
Operator plugins live under plugins/. A project directory of the same
name replaces the home plugin as a whole. plugin.json field enabled
(default true) omits a plugin without deleting it. config.json field
plugins enables discovery (default true). Each plugin also gets
runtime-data directories under data/plugins/. See
docs/plugins.md.
Dotnet tool sets load class
libraries from the set directory only, in one AssemblyLoadContext per
set.
Provider names are open. deepseek, openai, gemini, and ollama are starter entries. A user
adds an endpoint by inserting another providers object with protocol
deepseek, openai, responses, anthropic, gemini, or ollama, a baseUri, and a models
table. A gateway with different wire formats uses one provider name whose value
is an array of endpoint objects, one per protocol. Model ids must be unique
across that array; duplicates fail configuration loading. A selected model
determines the endpoint, protocol, and credentials used by the adapter.
Repeated JSON provider keys are rejected; the array form preserves both
endpoints. Repeated model keys within one endpoint are also rejected.
Context size and sampling live on each model, not
on the host. Thinking capability also lives on the model. The current thinking
gear is a host setting. An endpoint may also carry an options object of
JSON scalars. The object is not a fixed field list: names are read from the
JSON and interpreted by protocol. Unknown names fail loading. The only
recognized name is Anthropic thinkingDisplay, summarized (the default,
not written back) or omitted (do not send display). Sampling parameters
do not belong there. The API key for openrouter belongs in
credentials.json under that provider name.
{ "provider": "openrouter", "model": "anthropic/claude-sonnet-4", "thinkingEffort": "high", "skills": true, "providers": { "openrouter": { "protocol": "openai", "baseUri": "https://openrouter.ai/api/v1/", "replayReasoningContent": true, "tokenLimit": "max_tokens", "models": { "anthropic/claude-sonnet-4": { "contextWindow": 200000, "temperature": 0.2, "maxTokens": 8192, "thinking": true, "thinkingEfforts": ["low", "medium", "high"] } } } }}For a mixed-protocol gateway, providers.openrouter may instead be an array:
{ "providers": { "openrouter": [ { "protocol": "anthropic", "baseUri": "https://gateway.example.test/anthropic/", "models": { "claude-model": { "contextWindow": 200000 } } }, { "protocol": "openai", "baseUri": "https://gateway.example.test/openai/", "models": { "gpt-model": { "contextWindow": 128000 } } } ] }}thinking and thinkingEfforts declare whether the model supports
thinking and which effort tokens it accepts. A token starts with a
letter and then uses only letters, digits, underscores, and hyphens.
The host stores every token in lowercase and does not interpret it.
max and maximum are different tokens. A case-sensitive wire value
cannot be spelled here. An empty thinkingEfforts list is on/off only. Built-in
DeepSeek V4 models enable thinking with low, high, and max. thinkingCanDisable defaults to true. Set it to
false when the model rejects a request to turn thinking off. Built-in
Gemini 3 models do. /thinking then omits Off. A stored Off gear falls
back to the provider default and the status bar shows Think Default.
An explicit /thinking off is refused.
serviceTiers and speeds declare the tokens a model accepts for service
tier and speed. A token starts with a letter and then uses only letters,
digits, underscores, and hyphens. The host stores every token in
lowercase and does not interpret it. default is an ordinary token when
the model lists it. An
unset slot is omitted from the request. /tier and /speed (alias
/fast) cycle the current model’s list, including the unset slot, or
select a listed token. Each choice is stored per model in
tierSelections and speedSelections. Switching is refused during a turn
or compaction. An empty list means that slot is not offered.
Chat Completions writes whichever one slot is set to service_tier and
rejects both when the client is created, because that protocol has one
field. The choice is not saved. OpenAI Responses does the same. Anthropic
Messages writes the service tier to service_tier and the speed to
speed. DeepSeek, Gemini, and Ollama reject either slot when the client
is created. A saved combination the protocol cannot send fails at startup.
The host does not read the
response back to see which value was applied, and it does not infer a
vendor from the endpoint address.
contextWindow remains the model’s maximum context size. An optional
contextWindows array declares selectable local context budgets, for example
"contextWindow": 1000000, "contextWindows": [272000, 1000000].
Values must be distinct positive integers no greater than contextWindow;
the host sorts them in ascending order. Without a nonempty array the sole
budget is contextWindow. The initial budget is the lowest declared value.
/context cycles the current model’s budgets; /context 272k, /context 1m,
and exact integer token counts select one explicitly. Invalid or unavailable
values are refused. Switching is refused during a turn or compaction.
crystal, crystal space, and crystal run accept --context for the
model selected at launch when that model declares more than one budget.
The text is the same as /context, and it must name a declared budget.
A model with one budget is rejected. The value changes only the live
selection for that model and is not written to contextSelections.
Switching models restores the other model’s saved budget. A later
/context still writes.
config.json.contextSelections remembers choices without rewriting provider
definitions. The stored form is a nested object,
{"provider": {"model": tokens}}; the older flat {"provider/model": tokens}
map is still read and is written back nested on the next save. Values must be
positive token counts, provider keys are normalized to lowercase, and model
ids stay byte-exact, so a model id that contains / is stored as written.
A removed or unsupported saved choice falls back to the lowest declared
budget. Switching models restores that model’s choice. Compaction, overflow
checks, usage events, /status, and CTX percentages use the selected budget.
Lowering it keeps the archive and allows
the existing pre-request compaction check to summarize before the next model
round. These budgets do not send provider-specific long-context parameters
and do not guarantee a billing threshold against token estimation errors or
large tool results.
thinkingEffort is the operator choice: default, off (none is
the same), or an effort token listed for that model. It is not stored on the model. /thinking (alias
/think) cycles the gear or sets one by name. /model never
fails because of thinking: if the model does not support thinking, requests omit reasoning
hints; if the stored gear is not in that model’s list, the request
uses the provider default and the stored choice is unchanged.
crystal run prints that fallback on its error stream and continues.
Each adapter forwards an effort token unchanged. openai and
responses are also the Chat Completions and Responses paths for
third-party gateways, so they do not rename maximum to xhigh.
List the spelling that endpoint accepts.
| Protocol | Effort token |
|---|---|
anthropic |
unchanged. Adaptive or budgeted thinking also sets display to summarized, unless the endpoint sets options.thinkingDisplay to omitted |
responses |
unchanged |
openai |
unchanged |
deepseek |
unchanged |
ollama |
unchanged |
| Gemini 3 | uppercased thinkingLevel |
| Gemini 2.5 | minimal, low, medium, and high map to fixed budgets. Any other token, including maximum, is rejected because the field is an integer |
skills enables the skill tool and available-skill guidance
(default true). Set it to false to disable skill discovery.
ruleFiles enables OpenCode-compatible rule files. global and project
each default to true. See the instruction discovery section.
externalTools enables operator tool set discovery (default true).
Set it to false to skip tools/ manifests.
plugins enables operator plugin discovery (default true).
Set it to false to skip plugins/ manifests. See
docs/plugins.md.
externalToolApproval selects whether author approval declarations
in tools.json take effect, independently for the Home and Project
sources. Each member is author or host; defaults are Home author
and Project host. The object is omitted from the written file when
both members are the defaults; otherwise only changed members are
written.
promptSet and promptAttachments are no longer preferences. A file that
still contains them is read, the values are ignored, and the next preference
save omits both keys. Selection lives in each directory’s prompt.json.
estimatedTokens shows a live four-characters-per-token estimate on
the progress row during Thinking and Writing (default false). The
label is prefixed with ~ so it is not mistaken for provider usage.
/tokens toggles it, or sets on / off. A successful change writes
estimatedTokens to config.json (true when on; omitted when off).
protocol is deepseek, openai, responses, anthropic, gemini, or ollama. Models that are not listed cannot be
selected. Automatically fetching model-list information from a provider is
deferred. There is no global context window.
A persistent key belongs in credentials.json as plain text, keyed by
provider name. apiKey on a provider definition may be a literal secret,
{env:NAME}, or {file:path} (relative to ~/.crystal or absolute, with
~ expanded). Process environment variables override both the definition
and the file. That override is for one launch or a CI runner.
requiresApiKey defaults to true, except for the native ollama protocol.
When false, a missing key resolves to empty text and the adapter omits its
authentication header. Provider-specific environment variables and explicit
credential references still take precedence; the shared CRYSTAL_API_KEY
is not applied to keyless endpoints.
Amazon Bedrock has no dedicated adapter in this build. Its OpenAI-compatible
Chat Completions endpoint can use the openai protocol with a Bedrock API key
and the regional /openai/v1/ base URI for models that support that API.
IAM SigV4 authentication would require a separate signing implementation;
it is not provided by the current bearer-token transport.