Hooks, raw hooks, and loading
本頁內容尚未翻譯。
Hooks run in plugin load order. The next hook sees the previous replacement. The same pipeline wraps built-in tools, other plugins, and external tools. A hook that throws is skipped with an English note.
| Hook | May | May not |
|---|---|---|
OnSessionStartedAsync / OnSessionEndedAsync |
Read workspace root, session id, and approval mode | Prompt the operator, or write config.json |
OnPrompt |
Append text to the instruction block | Replace Work, Plan, or Review |
OnUserMessageAsync |
Replace the user message before it is stored | Leave the stored message blank, or run for a side question |
OnTurnStartedAsync / OnTurnFinishedAsync |
Read the stored user text, mode, and, when the turn ends, the stop reason | Change the transcript |
TransformModelAsync |
Change user, assistant, or tool-result text for one outbound call, or drop image references already on an item | Reorder, add, or drop items, edit a system message, add an image, or write the archive |
OnModelResponseAsync |
Read the purpose, finish reason, returned items, and usage of one completed work, plan, side, or compaction call | Change the transcript, the archive, or the response the host uses |
OnToolCallAsync |
Replace the name or arguments | Change the call id, skip the call, or skip approval |
OnToolResultAsync |
Replace the text result and, on an image-capable turn, its images | Mark an approval as passed |
OnApproval |
Raise risk, or require another prompt | Lower the host risk, or auto-pass |
OnCompaction |
Append facts to the summary prompt or the summary body | Drop history, or replace the compactor |
A rewritten tool call is classified and approved again before it runs.
Text-only turns ignore images returned by OnToolResultAsync. Image
types are image/png, image/jpeg, image/gif, and image/webp.
TransformModelAsync sees the model transcript for a work, plan, or side
request, and the older turns about to be summarized, after every raw hook
has run. It does not see the approval review. Returned image lists may only
name attachments already on that item. The stored transcript and the
archive stay as they were, except for text replaced by
OnUserMessageAsync.
OnModelResponseAsync runs after one of those calls returns and before the
host commits that candidate or runs its tools. Approval review does not
call it. The host keeps the candidate it received.
TransformModelAsync changes only the items sent on that one call. The
stored transcript and the archive stay as they were. Rewriting user,
assistant, or tool-result text can make the model answer from a
conversation the operator did not store. A replacement that reorders,
adds, or drops items, changes a role or a tool call, or edits a system
message is skipped with an English note. Structural changes belong to raw
hooks.
Session start runs after the plugin load, and again when another coding
session becomes active. Session end runs when the session closes, when
/clear, /resume, or /fork replaces it, and before a /cd or
/space reload. The end callback still carries the workspace and session
being left. A resume that also changes workspace is one end and one start.
crystal run closes the session when the process finishes.
Raw hooks
Section titled “Raw hooks”A raw hook is a privileged, low-level extension point. IPluginRawHook
is a separate interface. A plugin registers raw hooks on
PluginContribution.RawHooks, apart from Hooks. The operator does not
approve them. The host writes one note for each plugin that registers
one, for example Plugin 'Acme' registered a raw hook.
Raw hooks run in plugin load order. The next raw hook sees the previous replacement. A raw hook that throws is skipped with an English note. The host does not hold a raw hook to the rules that bind ordinary hooks. It refuses only what it cannot represent.
| Raw hook | May | May not |
|---|---|---|
RebuildModelAsync |
For one outbound call, drop, reorder, add, or rewrite items of any kind. That includes the live system prompt, roles, tool calls, tool results, and reasoning, and it may split a call from its result | Repeat an item id, return empty reasoning text, name an image the session does not hold, add an image to a request that cannot carry images, or write the archive |
RewritePrompt |
Replace the composed system text for work, plan, review, or compaction with any string, including an empty one. Work and plan text becomes the live system message and is archived |
Write ~/.crystal/prompts |
RewriteCompaction |
Replace the compaction user prompt, or the summary body that is stored, with any string, including an empty one | Choose which history is folded, or replace the compactor |
RewriteApproval |
After ordinary approval hooks, set any risk, any authority, any summary, and either prompt requirement. The approval policy then uses that classification | Skip that policy |
RebuildModelAsync sees the same requests as TransformModelAsync and
runs first. The stored transcript and the archive stay as they were.
- Ids. An item keeps the id the host gave it. A new item needs an id the request does not use. An id that returns with a different kind of item is a new item.
- New items. A new tool result ignores its
Name, which the host derives from the call. New reasoning carries text only, with no provider state. Rewriting the text of existing reasoning drops that state too. - Images. The host stores image bytes in the session and references
them by marker. A raw hook can keep, drop, or move an attachment that is
already in the request, with the same media type. It cannot create an
image.
PluginModelImagecarries no bytes. Support for new images is planned. Only user messages and tool results carry images to the model. Images on assistant and system messages become plain text.PluginModelRequest.AcceptsImagesis true only for a work or plan call on an image-capable model. Text-only turns, side questions, and compaction never send images, so the host skips a replacement that adds one there. - Provider rules. The host does not check what a provider accepts. A
request that splits a tool call from its result, or moves the system
prompt, can be rejected by the provider. When a work or plan call fails
after a raw hook changed its request, the host writes a note such as
Raw hook 'Acme' changed this model request. The failure may be related.The note is a hint, not a diagnosis. - Prompt text.
OnPromptstill only appends.RewritePromptthen replaces the composed system text for that mode. Any returned string is used, including an empty one. Work and plan text is what the session stores. The files under~/.crystal/promptsstay as the operator saved them.RebuildModelAsynccan still change the system item of one outbound call after that, without writing the archive. - Compaction text.
OnCompactionstill only appends.RewriteCompactionthen replaces the full compaction user prompt or the stored summary body. An empty replacement is kept. - Approval.
OnApprovalcan still only raise risk or require another prompt.RewriteApprovalthen replaces the classification and may lower risk, change authority, change the summary, or clear the prompt requirement. The approval policy uses the result.
More hook methods will be added later. A new method joins IPluginHook or
IPluginRawHook when its behavior is defined. This build does not reserve
empty methods for them. Whether plugins declare dependencies on one another,
and related loading questions, are under consideration and are not decided.
Load context
Section titled “Load context”Each plugin gets one non-collectible AssemblyLoadContext.
Shared assemblies come from the host: Crystal, Crystal.Tools,
CrystalCode.Tools, and CrystalCode.Plugins. Other dependencies must
resolve inside the plugin directory. The host does not probe the NuGet
cache or the workspace.
CrystalCode, CrystalCode.Engine, CrystalCode.Display, and
CrystalCode.Providers are refused, including as the entry assembly.
The context is not collectible. There is no hot reload, signing check,
or marketplace.
Not included
Section titled “Not included”- MCP.
- Collectible unload and hot reload.
- Replacing a built-in protocol, built-in tool, or built-in slash verb.
- Hooks on external tool sets.
- A module system below plugins and raw hooks. A later one may reach the host through reflection or another mechanism. Its behavior and ownership are not defined, and this build does not reserve types for it.