Skip to content

Architecture

xsyetopz edited this page Oct 13, 2026 · 4 revisions

Architecture

This page is the map of dotclaude 1.0.0. It is for a contributor who edits the code, the slices, or the generated files. It covers the kernel, the slices of the core plugin dotclaude, and the one hook module. It also covers the 11 events, the path from src/ to plugins/, and the seven add-on plugins. The core plugin is also the reference for the parts that you copy from the settings snippet. The Claude Code side of each event is on Hook-Events.

Folder Map

dotclaude has three folders of code.

  • The kernel, in src/kernel/, holds the code that the plugins share.
  • The slices, in src/plugins/<plugin>/slices/<s>/, hold the features.
  • The plugins, in plugins/<plugin>/, are the output of just generate. Claude Code loads these folders. Do not edit them by hand.

Parts of a Slice

Each slice has one slice.ts. It names what the slice adds to its plugin. The other parts depend on the slice.

  • domain/ holds the logic of the slice.
  • adapters/ connects the domain to an entry point, such as mod.ts for the mod handlers.
  • limits.ts holds the bounds of the slice.
  • The ports are the interfaces that the domain needs. The shared ports are in src/kernel/ports.ts.
  • lab/ holds the hook lab tests. skills/ holds the skill files.

The contract of a slice is in src/kernel/slice.ts. A mod handler has an event, an optional filter, a phase, and a run function. The phases run in this order: observe, normalize, rewrite, check, and answer.

Kernel

File What it holds
src/kernel/slice.ts The slice contract, the PHASES order, and the types of a mod handler and a classic hook. It has no runtime import.
src/kernel/budget.ts The shared runtime bounds, such as CONTEXT_WINDOW and BASH_OUTPUT_MAX_CHARS.
src/kernel/paths.ts The paths of the files that dotclaude reads or writes. It has no import.
src/kernel/temp-paths.ts The names of the scratch folders in the temp folder.
src/kernel/errors.ts The error policy. A catch names the errors that it expects, and it passes the others on.
src/kernel/model.ts The parts of a Claude model id.
src/kernel/ports.ts The interfaces that a CLI or a test replaces with an adapter or a fake.
src/kernel/node/ The adapters of the Node and Bun runtimes, such as fs.ts, hook-io.ts, and process.ts.
src/kernel/shell.ts, shellkinds.ts, wrappers.ts The shell reader. It reads the syntax that decides which command runs, and it does not run a shell.
src/kernel/rules.ts The checks of rule files in .claude/rules/ that need no model.
src/kernel/policy/ The catalog of the destructive floor. Each category is a file in rules/, and index.ts lists them.
src/kernel/spec-store.ts The format and the reader of the spec store file events.jsonl. Only the spec slice writes it.
src/kernel/skill-command.ts The rules of a mod handler that answers a skill command by running its CLI.

A hooks module imports only the kernel files that have no node: import. A hooks module has no Bun and no node: module. The generator copies each kernel file that a plugin imports into the plugin. So each plugin has its own copy.

Slices of the Core Plugin

The core plugin has 17 slices. The events column names the events that the slice declares in mod, in its slice.ts.

Slice What it does Events
agents Holds the six agent files, with the model and the effort of each. None
asks Asks before a change to a protected file, a git call that discards work, or an added skipped test or lint suppression. tool.check
attribution Adds the Co-Authored-By line to a git commit and the footer to a gh pr create body, with the model of the main loop. tool.call
checks The CLI dotclaude-run-checks, which runs check commands with no model turn. None
decide The tool second_opinion and the CLI dotclaude-decide, which ask Jev. session.start, tool.call
guard Denies a Bash command that only prints a file. Asks before the first call of a session that reaches a repository of another owner with an AI policy. tool.call, tool.check
handoff The handoff of the main session, and the note that tells a subagent to report before its bound. turn.step, tool.call, skill.prompt, turn.complete
prompt The system prompt of each model, the block at the end of a subagent task prompt, and the context_management section. prompt.compose, prompt.section, agent.spawn
rules The skill rules-creator. None
sembr Rewrites a tool.call on a Markdown file so that each sentence starts a line. tool.call
setup The skill setup, the CLI dotclaude-setup, and the drift check. session.start
spec The CLI dotclaude-spec, which writes the spec store, the handler that starts a package at implement, and the seven phase skills. agent.spawn
stamp Appends the dotclaude version and the short build SHA to the transcript at a session start, as a system notice, when the transcript has no stamp of that build yet. session.start
statusline The CLI dotclaude-statusline and its segments. None
styles The output style dotclaude:Concise. None
surface Shortens the descriptions of the built-in tools, and drops built-in agent types from the listing and from dispatch. agent.offer, tool.describe
trim The settings and env entries that turn off each built-in part that dotclaude removes. None

The statusline slice and the styles slice declare no mod handler. Their parts go to Claude Code as a status line command and an output style.

The 11 Events

The core plugin uses 11 events. Each event has one or more mod handlers. Each handler names its phase.

Event Slice and phase
session.start decide (observe), setup (observe)
tool.check asks (check), guard (check)
tool.call decide (rewrite, answer), guard (check), handoff (observe), sembr (rewrite)
prompt.compose prompt (rewrite)
prompt.section prompt (answer)
agent.spawn prompt (rewrite), spec (observe)
turn.step handoff (observe)
turn.complete handoff (observe)
skill.prompt handoff (rewrite)
tool.describe surface (answer)
agent.offer surface (answer)

The 19 mod handlers of the core plugin become 19 on() calls in one file. The generator writes that file as plugins/dotclaude/hooks/register.ts. It sorts the calls by event, then by phase, then by slice name, then by filter, in tools/generate/order.ts.

Known Open Point: the Filter of a tool.call Handler

tools/generate/order.ts and the handoff slice say that the mod runtime refuses a handler that has no filter. The guard slice has one tool.call handler with no filter. register.ts registers it next to filtered handlers. This page does not state the refusal as a fact. A run of the runtime settles it. Hook-Events gives the Claude Code side.

The Hook Module

The core plugin has one hook module, plugins/dotclaude/hooks/register.ts. It is generated, so do not edit it. The file plugins/dotclaude/hooks/hooks.json lists only the module:

{"modules": ["./register.ts"]}

The core plugin has no classic command hook. The checks that the module runs are on Guards.

Drift Check

The session.start handler of the setup slice compares the active settings with the settings snippet. It appends one note to the conversation only when it finds a difference. The note asks Claude to tell you. It changes no setting.

Difference Line of the note
A built-in plugin of the snippet is not false in enabledPlugins. Names each plugin and the setting that turns it off.
A skill of the listing has the source syncedSkills. Gives the count and names syncClaudeAiSkills.
The Claude Code version is not 2.1.296. Gives the version and the tested version.
The policy source of the settings has a key. Reports that the guard is seated, and names the parts that it skips.
CLAUDE_CODE_EFFORT_LEVEL or CLAUDE_CODE_SUBAGENT_MODEL_FORCE is set. Reports that the model and effort of the agent files do not apply.

A fact that cannot be read gives no line. So a failed read cannot make a false report. The tested version is TESTED_VERSION in src/plugins/dotclaude/slices/setup/domain/facts.ts. The section ids, the plugin names, and the version are data that Claude Code does not document. Undocumented-Reads explains this.

Skills

The core plugin ships ten skills. Each one is user-invoked, with disable-model-invocation: true. So it has no listing line in a request.

Entry What it does
/dotclaude:accept Moves a change to accepted when each package is done or canceled.
/dotclaude:archive Merges the requirements of an accepted change into the specs.
/dotclaude:handoff Writes a handoff file, then starts a clean session that reads it.
/dotclaude:implement Starts one implementer for each ready package, then runs verify.
/dotclaude:merge Merges the branch of an approved package and moves it to done.
/dotclaude:plan Splits a specified change into packages and moves it to planned.
/dotclaude:review Starts one reviewer for each verified package and records the verdict.
/dotclaude:rules-creator Creates and improves rule files in .claude/rules/.
/dotclaude:setup Applies the settings snippet and checks the tools of the installed add-ons.
/dotclaude:specify Writes the requirements of a change and runs its gate.

A skill has a name and a description of 150 to 300 bytes together. The bounds are SKILL_META_LOW_BYTES and SKILL_META_HIGH_BYTES in tools/limits.ts. A skill above 300 bytes fails the size check. A skill below 150 bytes gives only an advisory.

Limits

Each bound is in one file, and tests pin the copies. The shared bounds are in src/kernel/budget.ts.

Bound Value File
Context window 300,000 tokens src/kernel/budget.ts (CONTEXT_WINDOW)
Status line colors Yellow at 75% and red at 90% of the window src/kernel/budget.ts (USAGE_LEVELS)
bashOutputMaxChars 4,000 characters src/kernel/budget.ts (BASH_OUTPUT_MAX_CHARS)
Policy gh call 5,000 ms src/kernel/budget.ts (POLICY_TIMEOUT_MS)
Policy text in the ask 2,000 characters src/kernel/budget.ts (POLICY_FILE_MAX_CHARS)
Subagent context 100,000 tokens, and 85,000 for Haiku 5.5 src/plugins/dotclaude/slices/handoff/limits.ts
Subagent report 400 words src/plugins/dotclaude/slices/handoff/limits.ts (REPORT_MAX_WORDS)
Size of a file that the asks checks read 1,000,000 bytes src/plugins/dotclaude/slices/asks/limits.ts
Rows of the status line 3 src/plugins/dotclaude/slices/statusline/limits.ts

The size of the first request is bounded in tools/limits.ts. The bounds are FIRST_REQUEST_LOW_BYTES to FIRST_REQUEST_HIGH_BYTES. The Plugin-Layout page explains the tiers.

From src/ to plugins/

just generate runs bun tools/generate/index.ts. It writes a generated file only when the content differs. just generate --check exits 1 and names each file that differs. The steps are these:

  1. tools/generate/discover.ts finds each src/plugins/<plugin>/slices/<s>/slice.ts, the plugin.ts of each plugin, and each adapters/mod.ts.
  2. tools/generate/order.ts orders the mod handlers. It refuses two handlers of one slice with the same event, filter, and phase.
  3. tools/generate/emit/register.ts writes hooks/register.ts.
  4. tools/generate/emit/hooks.ts writes hooks/hooks.json. tools/generate/emit/evals.ts writes evals/hooks.json.
  5. tools/generate/emit/manifest.ts writes .claude-plugin/plugin.json from plugin.ts. It takes the version from package.json.
  6. tools/generate/emit/slices.ts copies the skills, agents, styles, lab tests, and evals of each slice to the plugin folder. It also writes one launcher for each CLI.
  7. tools/generate/closure.ts copies each kernel file that a plugin imports to plugins/<plugin>/kernel/.
  8. tools/generate/emit/snippet.ts computes the settings snippet from the settings of the slices.
  9. tools/generate/emit/texts.ts writes every other file of src/ to the same path under plugins/ or wiki/. So src/wiki/dotclaude/Architecture.md gives wiki/dotclaude/Architecture.md. A src/fragments/ file gives no output. tools/generate/emit/fill.ts replaces each include line with a fragment of src/fragments/. It also replaces each bound name in double braces with its value.

The files under plugins/ have a header that names the source. A JSON file has no header, because JSON has no comment. A file in plugins/ that has no source fails the generator. The check just check runs just generate --check. So a change in src/ needs just generate before the commit.

Add-On Plugins

Seven add-on plugins sit next to the core plugin. Each one has its own tree under src/plugins/<name>/. Each one works without the core plugin.

Plugin Slices What it does
dotclaude-codegraph graph Gives Claude the code graph of a project, with the codegraph CLI. See Code-Graph.
dotclaude-browser browse, search Drives a real browser for Claude. See Browser.
dotclaude-docs docs Gets the current docs of a library with the ctx7 CLI. See Library-Docs.
dotclaude-sessions start-cost, usage Measures Claude Code sessions from their transcripts. See Sessions.
dotclaude-lab capture, eval-compare, sandbox, schema Has tools for plugin authors. See Lab.
dcc-plugin-agents-md agents Loads AGENTS.md files where Claude Code loads CLAUDE.md. See Agents-Md.
dcc-plugin-you-should-know notice Opt-in. Shows one thing to know before the first change of a turn. See You-Should-Know.

The add-ons import nothing from each other, and nothing from dotclaude. Each one imports only the kernel and the claude-code types. The generator copies the kernel files into the plugin. The overview of the add-ons is on Add-Ons.

Related Pages

Clone this wiki locally