Adds your own operating frame (a markdown file) to the system prompt in sessions that were not launched with it.

Adds your own operating frame to the system prompt. Write the frame once as a markdown file (who the agent is, how it should work, house rules) and this mod appends it to the system prompt of every session that was not already launched with it, for example a session opened from a desktop app or a plain claude in a terminal.
The file is read once per session start and added as a session-scoped system prompt section.
~/.claude/mods/frame.CLAUDE_CODE_PLUGIN_DIRS=/path/to/frame (colon-separate several) in the environment that starts Claude Code, or pass --plugin-dir /path/to/frame.~/.claude/frame.md (see frame.example.md for a starting shape), or point FRAME_FILE at another path.FRAME_SKIP=1: set this in a launcher that already passes the same file with --system-prompt-file, so the frame is not added twice.If the file is missing or empty the mod does nothing.
claude plugin validate .
Mods (function hooks) are an early-access feature of Claude Code and may change between releases without notice. Claude Code writes the type declarations into .claude-plugin/types/ itself when it loads the mod, so they are not included here. A long frame costs tokens in every session; keep it tight.
hooks/register.ts 24 lines1import type { Register } from 'claude-code'
2
3// frame: appends a markdown file to the system prompt of sessions that were not launched with it.
4// FRAME_FILE: path to the file (default: ~/.claude/frame.md).
5// FRAME_SKIP=1: do nothing in this session (use it in a launcher that already passes the file with --system-prompt-file).
6
7let frame: string | undefined
8
9export const register: Register = on => {
10 on('prompt.compose', async ($, e, next) => {
11 const composed = await next(e)
12 if ((await $.env.get('FRAME_SKIP')) === '1') return composed
13 if (frame === undefined) {
14 try {
15 let file = await $.env.get('FRAME_FILE')
16 if (!file) file = `${(await $.env.get('HOME')) ?? ''}/.claude/frame.md`
17 frame = await $.fs.read(file)
18 } catch { frame = '' }
19 }
20 if (!frame) return composed
21 return { sections: [...composed.sections, { id: 'frame:frame', text: frame, scope: 'session' as const }] }
22 })
23}
24