跳到內容
Crystal CodeDocs
繁繁體中文

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

config.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_HOME is 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, then CLAUDE.md, then CONTEXT.md). Every file of that name on the walk is appended. CLAUDE.md is used only when no AGENTS.md exists 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.