Pin an agent charter into the system prompt: skills-first workflow, per-language comment standards, commit format and branch discipline.

Claude Code Mod:给智能体立一份行为宪章,覆盖 skill 使用、注释规范、 提交格式、分支纪律。
宪章是静态文本(plus:agent-charter),默认追加在 shared 阵营末尾, 不花缓存、四 Mod 行为:
[模块][n/m]{【类型】【版本】中文\英文描述}(需求号)。charterMode: append(默认):保留引擎原 composition,工具说明和 安全边界都在,只加宪章。replace: constitutional charter 之外 全部丢掉——模型会变笨、工具会残、安全会裸奔,只给知道自己在干什么 的人用:
{ "charterMode": "replace" }
claude --plugin-dir mods/agent-charter
claude plugin test mods/agent-charter
claude plugin install plus@claudecode-plus-mod --scope userhooks/register.ts 43 lines1import type { On } from 'claude-code'
2
3import { CHARTER_ID, applyCharter, buildCharter, resolveCharterMode } from './charter'
4
5type CharterOptions = {
6 charterMode?: string
7 verbose?: boolean
8}
9
10function report($: unknown, message: string, verbose: boolean): void {
11 const ui = ($ as { ui: { log: (text: string, opts?: object) => void } }).ui
12 if (verbose) {
13 ui.log(message)
14 } else {
15 ui.log(message, { to: 'debug' })
16 }
17}
18
19/**
20 * Pins the agent charter into the system prompt. Append mode (default) keeps
21 * the engine's composition, tools and safety rails included, and adds the
22 * charter last among shared sections. Replace mode drops everything else:
23 * use it only when you accept a dumber, unguarded agent.
24 *
25 * @param on the engine's registrar
26 * @param options `charterMode` append or replace; `verbose` surfaces lines
27 */
28export function register(on: On, options: CharterOptions = {}): void {
29 const mode = resolveCharterMode(options.charterMode)
30 const verbose = options.verbose === true
31 const mine = { id: CHARTER_ID, text: buildCharter(), scope: 'shared' as const }
32
33 on('session.start', ($, e, next) => {
34 report($, `[agent-charter] active in ${mode} mode`, verbose)
35 return next(e)
36 })
37
38 on('prompt.compose', async (_$, e, next) => {
39 const out = await next(e)
40 return { sections: applyCharter(out.sections, mine, mode) }
41 })
42}
43hooks/charter.ts 86 lines1/**
2 * Agent charter: one static section pinned into the system prompt. Static on
3 * purpose, so it sits on the shared side of the cache boundary in append
4 * mode. Replace mode drops the engine's own composition entirely, tools
5 * included: only for operators who know what they are giving up.
6 */
7
8export const CHARTER_ID = 'plus:agent-charter'
9
10export type CharterMode = 'append' | 'replace'
11
12const CHARTER = [
13 '# 代理宪章',
14 '',
15 '## Skill 与 Plugin 优先',
16 '开工前先列出本次任务相关的 skill 和已装 plugin,有现成能力先用,不重复造轮子。',
17 '项目级 skill 优先于通用做法;调用了哪个 skill,在总结里注明。',
18 '不要臆造不存在的 skill、命令或 API,不确定就先查。',
19 '',
20 '## 注释规范(按语言)',
21 '注释只解释为什么,不解释是什么;禁止装饰性注释(分隔线、星号框、ASCII 艺术)。',
22 '- Java: Javadoc',
23 '- Python: Docstring',
24 '- C#: XML 文档注释',
25 '- PHP: PHPDoc',
26 '- C / C++: Doxygen',
27 '- Go: Go Doc,注释紧贴声明并以名称开头',
28 '- Rust: Rustdoc(/// 对外,//! 对内)',
29 '- Ruby: RDoc / YARD',
30 '- Kotlin: KDoc',
31 '',
32 '## 提交信息格式',
33 '严格遵守:[模块][n/m]{【类型】【版本】中文\\英文描述}(需求号)',
34 '示例:[鉴权][2/5]{【修复】【v2.3】登录超时 Login timeout}(REQ-1234)',
35 'n/m 是本次系列提交的序号与总数;无需求号时括号内写实际事由,不许空着。',
36 '',
37 '## 分支与 PR 纪律',
38 '每次修改从主分支切新分支,一事一分支,禁止直接在主分支上改。',
39 '自测通过、确认无误后才合并;合并后删除分支,不许堆积。',
40 'PR 必须讲清三件事:改了什么、为什么改、怎么验证的;缺任何一件都不许合。',
41].join('\n')
42
43/**
44 * @param raw the `charterMode` option as received, anything unexpected falls back
45 * @returns append by default, replace only when explicitly asked
46 */
47export function resolveCharterMode(raw: unknown): CharterMode {
48 if (raw === 'replace') {
49 return 'replace'
50 }
51 return 'append'
52}
53
54/**
55 * @returns the full charter text
56 */
57export function buildCharter(): string {
58 return CHARTER
59}
60
61export type ComposableSection = {
62 id: string
63 text: string
64 scope: 'shared' | 'session'
65}
66
67/**
68 * @param sections the engine's composed list, every shared one ahead of every session one
69 * @param mine the charter section to add
70 * @param mode append keeps the engine's composition and adds the charter last
71 * among shared; replace drops everything and returns the charter alone
72 * @returns the sections the model will read
73 */
74export function applyCharter(
75 sections: readonly ComposableSection[],
76 mine: ComposableSection,
77 mode: CharterMode,
78): ComposableSection[] {
79 if (mode === 'replace') {
80 return [mine]
81 }
82 const shared = sections.filter((section) => section.scope === 'shared')
83 const session = sections.filter((section) => section.scope !== 'shared')
84 return [...shared, mine, ...session]
85}
86