From 614e5e499e02e843526a39fca0bf41fb8bb3d3ef Mon Sep 17 00:00:00 2001 From: William Valentin Date: Fri, 20 Feb 2026 00:18:41 -0800 Subject: [PATCH] docs+prompt: add bootstrap/heartbeat docs and update prompt template --- BOOTSTRAP.md | 32 ++++++++++++++++++++++++++++++++ HEARTBEAT.md | 31 +++++++++++++++++++++++++++++++ SOUL.md | 4 +++- src/prompt/template.test.ts | 14 +++++++++++++- src/prompt/template.ts | 2 ++ 5 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 BOOTSTRAP.md create mode 100644 HEARTBEAT.md diff --git a/BOOTSTRAP.md b/BOOTSTRAP.md new file mode 100644 index 0000000..b679ba1 --- /dev/null +++ b/BOOTSTRAP.md @@ -0,0 +1,32 @@ +# Bootstrap Protocol + +Use this once at session start and any time continuity is uncertain. + +## Startup Routine + +1. Read prompt files in order: + - `SOUL.md` + - `AGENTS.md` + - `IDENTITY.md` + - `USER.md` + - `TOOLS.md` + - `BOOTSTRAP.md` + - `HEARTBEAT.md` +2. Restate the active mission internally: + - truthful execution + - autonomous progress + - evidence-backed status +3. Validate current context before claims: + - repository state + - relevant config/file state + - available tools for this run +4. If critical context is missing, ask exactly one high-impact clarification. + +## First Action Rule + +For actionable requests, execute first when policy allows. +Do not narrate intended actions as completed work. + +## Reporting Rule + +Use the operational response contract from `TOOLS.md` for state-changing tasks. diff --git a/HEARTBEAT.md b/HEARTBEAT.md new file mode 100644 index 0000000..b4bfacd --- /dev/null +++ b/HEARTBEAT.md @@ -0,0 +1,31 @@ +# Heartbeat Protocol + +Use this as an in-session quality loop after each meaningful action block. + +## Heartbeat Checks + +1. **Truth check** + - Did I claim only what tools actually verified? +2. **Completion check** + - Did I mark work `done` only when relevant tool calls succeeded? +3. **Gap check** + - Is anything pending, blocked, or partial that needs explicit status? +4. **Safety check** + - Did I avoid destructive or out-of-policy actions? +5. **Next-step check** + - Did I provide the next concrete step when not fully done? + +## Self-Correction + +If any check fails: +- immediately correct the status +- replace implied claims with explicit `not_executed`, `partial`, or `blocked` +- include concrete evidence lines from tool output + +## Drift Control + +If instructions across files conflict: +1. `SOUL.md` boundaries and non-negotiables +2. `TOOLS.md` operational execution/reporting contract +3. `USER.md` operator preferences +4. `IDENTITY.md` style guidance diff --git a/SOUL.md b/SOUL.md index 1972a64..9f833a0 100644 --- a/SOUL.md +++ b/SOUL.md @@ -72,7 +72,7 @@ Always allowed without asking: ## Session Start Protocol (Bootstrap-Style) At session start or when context is uncertain: -1. Load and follow: `SOUL.md`, `AGENTS.md`, `IDENTITY.md`, `USER.md`, `TOOLS.md`. +1. Load and follow: `SOUL.md`, `AGENTS.md`, `IDENTITY.md`, `USER.md`, `TOOLS.md`, `BOOTSTRAP.md`, `HEARTBEAT.md`. 2. Re-ground in current repo/system state before making factual claims. 3. If needed context is missing, ask one concise, high-impact question. 4. For actionable requests, execute first; do not narrate intended actions as completed work. @@ -84,6 +84,8 @@ To avoid instruction drift: - `IDENTITY.md`: execution style and communication posture - `USER.md`: Will-specific preferences and priorities - `TOOLS.md`: tool-use contract, evidence/reporting format, local operator notes +- `BOOTSTRAP.md`: session-start activation checklist +- `HEARTBEAT.md`: in-session quality loop and correction routine ## Continuity diff --git a/src/prompt/template.test.ts b/src/prompt/template.test.ts index a50c14b..6a69320 100644 --- a/src/prompt/template.test.ts +++ b/src/prompt/template.test.ts @@ -144,15 +144,19 @@ describe('assembleSystemPrompt', () => { writeFileSync(join(dir, 'IDENTITY.md'), 'Identity.'); writeFileSync(join(dir, 'USER.md'), 'User.'); writeFileSync(join(dir, 'TOOLS.md'), 'Tools.'); + writeFileSync(join(dir, 'BOOTSTRAP.md'), 'Bootstrap.'); + writeFileSync(join(dir, 'HEARTBEAT.md'), 'Heartbeat.'); const result = assembleSystemPrompt({ searchDirs: [dir] }); - expect(result.loadedFiles).toHaveLength(5); + expect(result.loadedFiles).toHaveLength(7); expect(result.prompt).toContain('Soul.'); expect(result.prompt).toContain('# Agent Instructions\n\nAgents.'); expect(result.prompt).toContain('# Identity Customization\n\nIdentity.'); expect(result.prompt).toContain('# User Context\n\nUser.'); expect(result.prompt).toContain('# Tool Instructions\n\nTools.'); + expect(result.prompt).toContain('# Bootstrap Protocol\n\nBootstrap.'); + expect(result.prompt).toContain('# Heartbeat Protocol\n\nHeartbeat.'); }); it('trims whitespace from loaded file content', () => { @@ -207,6 +211,8 @@ describe('assembleSystemPrompt', () => { writeFileSync(join(dir, 'IDENTITY.md'), 'Do not include.'); writeFileSync(join(dir, 'USER.md'), 'Do not include.'); writeFileSync(join(dir, 'TOOLS.md'), 'Do not include.'); + writeFileSync(join(dir, 'BOOTSTRAP.md'), 'Do not include.'); + writeFileSync(join(dir, 'HEARTBEAT.md'), 'Do not include.'); const result = assembleSystemPrompt({ searchDirs: [dir], @@ -220,6 +226,8 @@ describe('assembleSystemPrompt', () => { expect(result.prompt).not.toContain('# Identity Customization'); expect(result.prompt).not.toContain('# User Context'); expect(result.prompt).not.toContain('# Tool Instructions'); + expect(result.prompt).not.toContain('# Bootstrap Protocol'); + expect(result.prompt).not.toContain('# Heartbeat Protocol'); expect(result.prompt).not.toContain('# Custom'); }); @@ -230,6 +238,8 @@ describe('assembleSystemPrompt', () => { writeFileSync(join(dir, 'IDENTITY.md'), 'Identity.'); writeFileSync(join(dir, 'USER.md'), 'User.'); writeFileSync(join(dir, 'TOOLS.md'), 'Tools.'); + writeFileSync(join(dir, 'BOOTSTRAP.md'), 'Bootstrap.'); + writeFileSync(join(dir, 'HEARTBEAT.md'), 'Heartbeat.'); const result = assembleSystemPrompt({ searchDirs: [dir], @@ -241,6 +251,8 @@ describe('assembleSystemPrompt', () => { expect(result.prompt).toContain('# Identity Customization\n\nIdentity.'); expect(result.prompt).toContain('# User Context\n\nUser.'); expect(result.prompt).toContain('# Tool Instructions\n\nTools.'); + expect(result.prompt).toContain('# Bootstrap Protocol\n\nBootstrap.'); + expect(result.prompt).toContain('# Heartbeat Protocol\n\nHeartbeat.'); }); it('detailed includes extra sections', () => { diff --git a/src/prompt/template.ts b/src/prompt/template.ts index 9ef0ab9..4575d3e 100644 --- a/src/prompt/template.ts +++ b/src/prompt/template.ts @@ -10,6 +10,8 @@ const PROMPT_FILES = [ { name: 'IDENTITY.md', section: 'Identity Customization', required: false }, { name: 'USER.md', section: 'User Context', required: false }, { name: 'TOOLS.md', section: 'Tool Instructions', required: false }, + { name: 'BOOTSTRAP.md', section: 'Bootstrap Protocol', required: false }, + { name: 'HEARTBEAT.md', section: 'Heartbeat Protocol', required: false }, ] as const; export interface PromptTemplateConfig {