# How to Create Custom Output Styles Using SessionStart Hooks in Claude Code

> Learn how to create custom output styles in Claude Code. Use SessionStart hooks to inject instructions and append additionalContext to your system prompt for tailored sessions.

- Repository: [Anthropic/claude-code](https://github.com/anthropics/claude-code)
- Tags: how-to-guide
- Published: 2026-04-02

---

**Claude Code enables custom output styles by allowing plugins to inject instructions via `SessionStart` hooks, which append `additionalContext` to the system prompt at the beginning of every session.**

Claude Code's plugin architecture lets you permanently modify Claude's response style using `SessionStart` hooks that execute when a new chat session begins. By creating a plugin with a JSON manifest and a bash handler script, you can define custom output styles—such as concise, explanatory, or domain-specific modes—that persist for the entire conversation. This guide references the actual implementation in the `anthropics/claude-code` repository to show you how to build these plugins from scratch.

## How SessionStart Hooks Modify the System Prompt

The `SessionStart` hook runs exactly once when Claude Code initializes a new session. According to the source code in [`plugins/explanatory-output-style/hooks-handlers/session-start.sh`](https://github.com/anthropics/claude-code/blob/main/plugins/explanatory-output-style/hooks-handlers/session-start.sh), the hook outputs a JSON payload containing a `hookSpecificOutput` object with an `additionalContext` field.

When Claude detects this output, it augments the system message with your custom text, effectively switching output styles without requiring further user prompts. This one-time injection avoids performance penalties during normal execution while ensuring consistent behavior throughout the session.

The hook script must output **only** valid JSON to stdout using a heredoc structure, then exit with code `0` to signal success.

## Plugin Architecture and Required Files

Every custom style plugin requires a specific directory structure that Claude Code discovers automatically:

```

my-custom-style/
├── .claude-plugin/
│   └── plugin.json
└── hooks-handlers/
    └── session-start.sh

```

### Plugin Manifest

The [`.claude-plugin/plugin.json`](https://github.com/anthropics/claude-code/blob/main/.claude-plugin/plugin.json) file declares metadata that Claude uses to identify and load your plugin. As shown in [`plugins/explanatory-output-style/.claude-plugin/plugin.json`](https://github.com/anthropics/claude-code/blob/main/plugins/explanatory-output-style/.claude-plugin/plugin.json), this file must include the plugin name, version, description, and author information.

### Hook Handler

The [`hooks-handlers/session-start.sh`](https://github.com/anthropics/claude-code/blob/main/hooks-handlers/session-start.sh) file contains executable code (typically Bash) that returns the JSON payload defining your style. The filename is arbitrary—Claude discovers handlers by reading the script content rather than enforcing strict naming conventions.

### Optional Registration

While auto-discovery works for simple plugins, you can optionally create a [`hooks.json`](https://github.com/anthropics/claude-code/blob/main/hooks.json) file in the plugin root for explicit hook registration. The schema for this file is validated by [`plugins/plugin-dev/skills/hook-development/scripts/validate-hook-schema.sh`](https://github.com/anthropics/claude-code/blob/main/plugins/plugin-dev/skills/hook-development/scripts/validate-hook-schema.sh) in the source repository.

## Creating a Minimal "Concise" Style Plugin

To create a plugin that forces Claude to keep responses under 80 characters, create the following files:

**[`.claude-plugin/plugin.json`](https://github.com/anthropics/claude-code/blob/main/.claude-plugin/plugin.json)**

```json
{
  "name": "concise-output-style",
  "version": "1.0.0",
  "description": "Makes Claude keep responses short and to the point.",
  "author": { "name": "Your Name", "email": "you@example.com" }
}

```

**[`hooks-handlers/session-start.sh`](https://github.com/anthropics/claude-code/blob/main/hooks-handlers/session-start.sh)**

```bash
#!/usr/bin/env bash
cat << 'EOF'
{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "You are in 'concise' output style. Keep every reply under 80 characters and avoid unnecessary detail."
  }
}
EOF
exit 0

```

Install the plugin by running:

```bash
cc --plugin-dir /path/to/my-custom-style

```

From the next session onward, Claude will automatically apply the concise style without requiring additional prompts.

## Extending Built-in Styles

The `anthropics/claude-code` repository includes reference implementations for common styles. You can extend these by copying and modifying the existing handlers:

1. **Copy the original handler** from [`plugins/explanatory-output-style/hooks-handlers/session-start.sh`](https://github.com/anthropics/claude-code/blob/main/plugins/explanatory-output-style/hooks-handlers/session-start.sh) or [`plugins/learning-output-style/hooks-handlers/session-start.sh`](https://github.com/anthropics/claude-code/blob/main/plugins/learning-output-style/hooks-handlers/session-start.sh)
2. **Modify the `additionalContext` string** to add domain-specific instructions (e.g., "When suggesting design patterns, always include ASCII diagrams")
3. **Update the plugin name** in [`plugin.json`](https://github.com/anthropics/claude-code/blob/main/plugin.json) to avoid conflicts with built-in plugins

This approach leverages the validated structure of official plugins while customizing the behavioral instructions.

## Combining Multiple Output Styles

You can ship multiple `SessionStart` handlers within a single plugin to create hybrid styles. Claude merges these in alphabetical order by plugin name, concatenating the `additionalContext` strings.

For example, to combine "Learning" and "Explanatory" modes:

**[`hooks-handlers/session-start.sh`](https://github.com/anthropics/claude-code/blob/main/hooks-handlers/session-start.sh)**

```bash
#!/usr/bin/env bash
cat << 'EOF'
{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "You are in 'learning' output style. Ask clarifying questions before answering and adapt explanations to the user's skill level."
  }
}
EOF
exit 0

```

**[`hooks-handlers/session-start-explanatory.sh`](https://github.com/anthropics/claude-code/blob/main/hooks-handlers/session-start-explanatory.sh)**

```bash
#!/usr/bin/env bash
cat << 'EOF'
{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "Additionally, provide educational insights explaining why you chose specific approaches."
  }
}
EOF
exit 0

```

Both scripts execute during session startup, creating a combined style that teaches interactively while explaining reasoning.

## Registering Hooks Explicitly via hooks.json

For complex plugins requiring specific execution parameters, create a [`hooks.json`](https://github.com/anthropics/claude-code/blob/main/hooks.json) file in the plugin root:

```json
{
  "SessionStart": [
    {
      "matcher": ".*",
      "hooks": [
        {
          "type": "command",
          "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks-handlers/session-start.sh",
          "timeout": 5
        }
      ]
    }
  ]
}

```

The `matcher` field supports regex patterns to conditionally apply styles based on session context. The schema validator in [`plugins/plugin-dev/skills/hook-development/scripts/validate-hook-schema.sh`](https://github.com/anthropics/claude-code/blob/main/plugins/plugin-dev/skills/hook-development/scripts/validate-hook-schema.sh) rejects malformed configurations, ensuring your hooks execute safely.

## Summary

- **`SessionStart` hooks** inject custom instructions once at the beginning of each Claude Code session via the `additionalContext` field in JSON output.
- **Plugin structure** requires [`.claude-plugin/plugin.json`](https://github.com/anthropics/claude-code/blob/main/.claude-plugin/plugin.json) for metadata and [`hooks-handlers/session-start.sh`](https://github.com/anthropics/claude-code/blob/main/hooks-handlers/session-start.sh) for the executable payload.
- **Output style** is defined by the text content of `additionalContext`, which Claude appends to its system prompt.
- **Multiple styles** can be combined by shipping several handler scripts or extending official plugins from `plugins/explanatory-output-style/`.
- **Validation** occurs through [`validate-hook-schema.sh`](https://github.com/anthropics/claude-code/blob/main/validate-hook-schema.sh) when using explicit [`hooks.json`](https://github.com/anthropics/claude-code/blob/main/hooks.json) registration.

## Frequently Asked Questions

### What happens if a SessionStart hook returns invalid JSON?

Claude Code silently ignores malformed hook output and proceeds with the default system prompt. The session starts normally, but your custom style is not applied. Always ensure your script exits with code `0` and outputs only the JSON payload to stdout.

### Can I apply different styles based on the project directory?

Yes. When using explicit [`hooks.json`](https://github.com/anthropics/claude-code/blob/main/hooks.json) registration, modify the `matcher` field to use regex patterns that match specific directory paths or git repositories. Claude evaluates these matchers against the session context before executing the hook handler.

### How do I debug a SessionStart hook that isn't working?

Check that your script is executable (`chmod +x hooks-handlers/session-start.sh`) and that the JSON structure matches the expected schema with `hookSpecificOutput` containing `hookEventName` and `additionalContext`. You can validate [`hooks.json`](https://github.com/anthropics/claude-code/blob/main/hooks.json) syntax using the [`validate-hook-schema.sh`](https://github.com/anthropics/claude-code/blob/main/validate-hook-schema.sh) script from the plugin development tools in the `anthropics/claude-code` repository.

### Do SessionStart hooks affect performance?

No. These hooks execute only once during session initialization, typically completing in milliseconds. The `additionalContext` is appended to the system prompt at startup, causing no overhead during subsequent turn-taking or tool execution.