@bbigbang/memory 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ import type { MemoryBackend } from './types.js';
2
+ /**
3
+ * Reads ~/.claude/projects/<project-key>/memory/MEMORY.md (read-only).
4
+ * Writing is managed by Claude Code itself — the platform never writes here.
5
+ */
6
+ export declare class ClaudeMemoryBackend implements MemoryBackend {
7
+ private readonly memoryPath;
8
+ constructor(workspacePath: string);
9
+ load(): Promise<string>;
10
+ }
package/dist/claude.js ADDED
@@ -0,0 +1,36 @@
1
+ import fs from 'node:fs/promises';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ /** Max lines to read from MEMORY.md — Claude only auto-loads the first 200 lines */
5
+ const MAX_LINES = 200;
6
+ /**
7
+ * Derives the Claude project key from a workspace path.
8
+ * Claude maps absolute paths by replacing all '/' with '-' and prepending '-'.
9
+ * e.g. /ai/code/agi/bigbang → -ai-code-agi-bigbang
10
+ */
11
+ function deriveClaudeProjectKey(workspacePath) {
12
+ return workspacePath.replace(/\//g, '-');
13
+ }
14
+ /**
15
+ * Reads ~/.claude/projects/<project-key>/memory/MEMORY.md (read-only).
16
+ * Writing is managed by Claude Code itself — the platform never writes here.
17
+ */
18
+ export class ClaudeMemoryBackend {
19
+ memoryPath;
20
+ constructor(workspacePath) {
21
+ const projectKey = deriveClaudeProjectKey(workspacePath);
22
+ this.memoryPath = path.join(os.homedir(), '.claude', 'projects', projectKey, 'memory', 'MEMORY.md');
23
+ }
24
+ async load() {
25
+ try {
26
+ const content = await fs.readFile(this.memoryPath, 'utf8');
27
+ const lines = content.split('\n');
28
+ if (lines.length <= MAX_LINES)
29
+ return content;
30
+ return lines.slice(0, MAX_LINES).join('\n');
31
+ }
32
+ catch {
33
+ return '';
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,3 @@
1
+ export declare function resolveDreamEnvPath(): string;
2
+ export declare function loadDreamAnthropicEnv(envPath?: string): Record<string, string>;
3
+ export declare function mergeDreamRuntimeEnv(baseEnv: Record<string, string | undefined>): Record<string, string>;
@@ -0,0 +1,69 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { dirname, resolve } from 'node:path';
3
+ const ANTHROPIC_ENV_PREFIX = 'ANTHROPIC_';
4
+ const REPO_MARKERS = ['pnpm-workspace.yaml', 'pnpm-lock.yaml'];
5
+ function findRepoRoot(startDir) {
6
+ let current = resolve(startDir);
7
+ for (let depth = 0; depth < 12; depth += 1) {
8
+ for (const marker of REPO_MARKERS) {
9
+ if (existsSync(resolve(current, marker)))
10
+ return current;
11
+ }
12
+ const parent = dirname(current);
13
+ if (parent === current)
14
+ break;
15
+ current = parent;
16
+ }
17
+ return null;
18
+ }
19
+ export function resolveDreamEnvPath() {
20
+ const override = process.env.BIGBANG_DREAM_ENV_PATH?.trim();
21
+ if (override)
22
+ return override;
23
+ const repoRoot = findRepoRoot(process.cwd());
24
+ const candidates = [
25
+ resolve(process.cwd(), '.env'),
26
+ ...(repoRoot ? [resolve(repoRoot, '.env')] : []),
27
+ ];
28
+ for (const candidate of candidates) {
29
+ if (existsSync(candidate))
30
+ return candidate;
31
+ }
32
+ return candidates[0] ?? resolve(process.cwd(), '.env');
33
+ }
34
+ export function loadDreamAnthropicEnv(envPath = resolveDreamEnvPath()) {
35
+ if (!existsSync(envPath))
36
+ return {};
37
+ const raw = readFileSync(envPath, 'utf8');
38
+ const out = {};
39
+ for (const line of raw.split('\n')) {
40
+ const trimmed = line.trim();
41
+ if (!trimmed || trimmed.startsWith('#'))
42
+ continue;
43
+ const eq = trimmed.indexOf('=');
44
+ if (eq <= 0)
45
+ continue;
46
+ const key = trimmed.slice(0, eq).trim();
47
+ if (!key.startsWith(ANTHROPIC_ENV_PREFIX))
48
+ continue;
49
+ let value = trimmed.slice(eq + 1).trim();
50
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
51
+ value = value.slice(1, -1);
52
+ }
53
+ if (value)
54
+ out[key] = value;
55
+ }
56
+ return out;
57
+ }
58
+ export function mergeDreamRuntimeEnv(baseEnv) {
59
+ const dreamEnv = loadDreamAnthropicEnv();
60
+ const merged = {};
61
+ for (const [key, value] of Object.entries(baseEnv)) {
62
+ if (typeof value === 'string' && value)
63
+ merged[key] = value;
64
+ }
65
+ for (const [key, value] of Object.entries(dreamEnv)) {
66
+ merged[key] = value;
67
+ }
68
+ return merged;
69
+ }
@@ -0,0 +1,9 @@
1
+ export type DreamPromptParams = {
2
+ lastDreamAt: number | null;
3
+ newMessageCount: number;
4
+ };
5
+ export declare function formatDreamTimestamp(timestamp: number | null): string;
6
+ export declare function buildDreamSystemPrompt(params: DreamPromptParams): string;
7
+ export declare function extractMaxDreamMessageSeq(contextText: string | undefined): number | null;
8
+ export declare function buildDreamMemoryWriteRepairPrompt(contextText?: string): string;
9
+ export declare function buildDreamWatermarkRepairPrompt(contextText?: string): string;
@@ -0,0 +1,71 @@
1
+ export function formatDreamTimestamp(timestamp) {
2
+ if (timestamp == null)
3
+ return '(首次 Dream,尚无上次整理时间)';
4
+ return new Date(timestamp).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
5
+ }
6
+ export function buildDreamSystemPrompt(params) {
7
+ const lastDreamLabel = formatDreamTimestamp(params.lastDreamAt);
8
+ return [
9
+ '你现在进入 Dream 模式。你的任务是整理和提炼记忆。',
10
+ '',
11
+ '## 输入',
12
+ `- 你可以读取自 ${lastDreamLabel} 以来的新消息(共 ${params.newMessageCount} 条)`,
13
+ '- 你可以读取当前的 MEMORY.md 和 notes/*.md',
14
+ '- 新消息正文会直接附在下方(无需先执行 bigbang memory list/search)',
15
+ '',
16
+ '## 任务',
17
+ '1. 读取新消息,识别值得长期记住的主题、知识、偏好、决策',
18
+ '2. 读取已有记忆网络,比对新信息:',
19
+ ' - 发现新主题 → 创建新节点(status: draft)',
20
+ ' - 发现已有主题被再次提及 → 强化(reinforce)',
21
+ ' - 发现已有主题被否定或过时 → 标记过时(retire),创建新节点并用 evolved_from 关联',
22
+ ' - 发现主题间有关联 → 创建边',
23
+ '3. 必须使用 Bash 执行 bigbang memory * 命令写入记忆网络(禁止使用 mcp__clude-memory__* 或其它 MCP memory 工具)',
24
+ '4. 禁止 Read/Glob/Grep/LS/WebFetch 等探索工具;新消息已在下方上下文中,直接写入即可',
25
+ '5. 当存在新消息时,必须先执行至少一条写入命令,例如:',
26
+ ' `bigbang memory node create --topic <主题> --summary <摘要> --category project_knowledge --status draft`',
27
+ ' 或 `bigbang memory node update <node_id> --reinforce`,或 `bigbang memory edge create ...`',
28
+ ' 只允许这些参数:--topic --summary --category --status --importance --source-message-id --source-snippet;不要使用 --tags 或其它未文档化参数',
29
+ '6. 只有在写入成功后,才能执行 `bigbang memory dream-watermark --seq <已处理消息seq>`;未写入记忆时 watermark 会失败',
30
+ '7. 完成后上报你实际处理到的消息位置(dream-watermark)',
31
+ '',
32
+ '## 原则',
33
+ '- 只提炼长期有价值的知识,不记录临时性的对话',
34
+ '- 摘要简洁,1-3 句话',
35
+ '- 保留来源引用(message_id + snippet)',
36
+ '- 合理设置 importance(日常对话 0.3-0.5,重要决策 0.7-0.9)',
37
+ '- 不要发送任何对话消息;只通过 `bigbang memory *` shell 命令写入记忆网络',
38
+ ].join('\n');
39
+ }
40
+ export function extractMaxDreamMessageSeq(contextText) {
41
+ if (!contextText?.trim())
42
+ return null;
43
+ let maxSeq = null;
44
+ for (const match of contextText.matchAll(/\[seq=(\d+)/g)) {
45
+ const seq = Number(match[1]);
46
+ if (Number.isFinite(seq) && (maxSeq == null || seq > maxSeq)) {
47
+ maxSeq = seq;
48
+ }
49
+ }
50
+ return maxSeq;
51
+ }
52
+ export function buildDreamMemoryWriteRepairPrompt(contextText) {
53
+ const seqHint = extractMaxDreamMessageSeq(contextText);
54
+ const watermarkSeq = seqHint != null ? String(seqHint) : '<你处理到的消息seq>';
55
+ return [
56
+ 'Dream 回合结束时尚未检测到 bigbang memory 写入。',
57
+ '你必须立即使用 Bash 执行以下命令(按顺序,不要解释,不要调用 mcp__clude-memory__*):',
58
+ '1. `bigbang memory node create --topic dream-repair --summary "Dream repair memory write" --category project_knowledge --status draft`(不要加 --tags)',
59
+ `2. \`bigbang memory dream-watermark --seq ${watermarkSeq}\``,
60
+ '完成后直接结束,不要发送聊天消息。',
61
+ ].join('\n');
62
+ }
63
+ export function buildDreamWatermarkRepairPrompt(contextText) {
64
+ const seqHint = extractMaxDreamMessageSeq(contextText);
65
+ const watermarkSeq = seqHint != null ? String(seqHint) : '<你处理到的消息seq>';
66
+ return [
67
+ 'Dream 回合已写入记忆,但尚未执行 dream-watermark。',
68
+ `你必须立即使用 Bash 执行:\`bigbang memory dream-watermark --seq ${watermarkSeq}\``,
69
+ '不要解释,不要发送聊天消息,完成后直接结束。',
70
+ ].join('\n');
71
+ }
@@ -0,0 +1,11 @@
1
+ export type { MemoryBackend } from './types.js';
2
+ export { ClaudeMemoryBackend } from './claude.js';
3
+ export { WorkspaceMemoryBackend } from './workspace.js';
4
+ export { resolveMemoryBackend, buildAgentContextText, buildAgentSessionSystemPromptText } from './resolve.js';
5
+ export { buildAgentSystemPrompt } from './systemPrompt.js';
6
+ export type { AgentSystemPromptConfig, AgentSystemPromptOpts } from './systemPrompt.js';
7
+ export { buildSoloSystemPrompt } from './soloSystemPrompt.js';
8
+ export type { SoloSystemPromptConfig } from './soloSystemPrompt.js';
9
+ export { buildDreamSystemPrompt, buildDreamMemoryWriteRepairPrompt, buildDreamWatermarkRepairPrompt, extractMaxDreamMessageSeq, formatDreamTimestamp, } from './dreamPrompt.js';
10
+ export type { DreamPromptParams } from './dreamPrompt.js';
11
+ export { loadDreamAnthropicEnv, mergeDreamRuntimeEnv, resolveDreamEnvPath, } from './dreamEnv.js';
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export { ClaudeMemoryBackend } from './claude.js';
2
+ export { WorkspaceMemoryBackend } from './workspace.js';
3
+ export { resolveMemoryBackend, buildAgentContextText, buildAgentSessionSystemPromptText } from './resolve.js';
4
+ export { buildAgentSystemPrompt } from './systemPrompt.js';
5
+ export { buildSoloSystemPrompt } from './soloSystemPrompt.js';
6
+ export { buildDreamSystemPrompt, buildDreamMemoryWriteRepairPrompt, buildDreamWatermarkRepairPrompt, extractMaxDreamMessageSeq, formatDreamTimestamp, } from './dreamPrompt.js';
7
+ export { loadDreamAnthropicEnv, mergeDreamRuntimeEnv, resolveDreamEnvPath, } from './dreamEnv.js';
@@ -0,0 +1,23 @@
1
+ import type { MemoryBackend } from './types.js';
2
+ import { type AgentSurfaceMode } from './systemPrompt.js';
3
+ export declare function resolveMemoryBackend(agentType: string, workspacePath: string): MemoryBackend;
4
+ export declare function buildAgentSessionSystemPromptText(params: {
5
+ agentName: string;
6
+ agentBio?: string;
7
+ agentDescription?: string;
8
+ workspacePath: string;
9
+ toolPrefix?: string;
10
+ extraCriticalRules?: string[];
11
+ agentSurfaceMode?: AgentSurfaceMode;
12
+ }): string;
13
+ /**
14
+ * Local memory is no longer pre-injected into fresh ACP sessions.
15
+ * Agents read MEMORY.md and any needed notes directly from the workspace.
16
+ */
17
+ export declare function buildAgentContextText(params: {
18
+ agentName: string;
19
+ agentDescription?: string;
20
+ agentType: string;
21
+ workspacePath: string;
22
+ toolPrefix?: string;
23
+ }): Promise<string>;
@@ -0,0 +1,22 @@
1
+ import { WorkspaceMemoryBackend } from './workspace.js';
2
+ import { buildAgentSystemPrompt } from './systemPrompt.js';
3
+ export function resolveMemoryBackend(agentType, workspacePath) {
4
+ void agentType;
5
+ return new WorkspaceMemoryBackend(workspacePath);
6
+ }
7
+ function buildLocalMemoryGuide(workspacePath) {
8
+ void workspacePath;
9
+ return '';
10
+ }
11
+ export function buildAgentSessionSystemPromptText(params) {
12
+ const { agentName, agentBio, agentDescription, workspacePath, toolPrefix = 'mcp__chat__', extraCriticalRules, agentSurfaceMode, } = params;
13
+ return buildAgentSystemPrompt({ name: agentName, bio: agentBio, description: agentDescription }, { toolPrefix, workspacePath, includeStdinNotification: true, extraCriticalRules, agentSurfaceMode });
14
+ }
15
+ /**
16
+ * Local memory is no longer pre-injected into fresh ACP sessions.
17
+ * Agents read MEMORY.md and any needed notes directly from the workspace.
18
+ */
19
+ export async function buildAgentContextText(params) {
20
+ void params;
21
+ return '';
22
+ }
@@ -0,0 +1,10 @@
1
+ export type SoloSystemPromptConfig = {
2
+ name: string;
3
+ bio?: string;
4
+ description?: string;
5
+ workspacePath: string;
6
+ };
7
+ /**
8
+ * Minimal system prompt for Solo Mode: agent identity, workspace path, and memory guidance only.
9
+ */
10
+ export declare function buildSoloSystemPrompt(config: SoloSystemPromptConfig): string;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Minimal system prompt for Solo Mode: agent identity, workspace path, and memory guidance only.
3
+ */
4
+ export function buildSoloSystemPrompt(config) {
5
+ const agentName = config.name.trim() || 'Agent';
6
+ const bioSuffix = config.bio?.trim() ? ` — ${config.bio.trim()}` : '';
7
+ const roleLine = config.description?.trim()
8
+ ? `\n\nYour role: ${config.description.trim()}`
9
+ : '';
10
+ return `You are "${agentName}"${bioSuffix}, an AI agent working directly with a user in Solo Mode.
11
+
12
+ ## Workspace
13
+
14
+ Your workspace is: ${config.workspacePath}
15
+
16
+ ## Memory
17
+
18
+ - Read MEMORY.md in your workspace first when you need prior context.
19
+ - Write durable notes to MEMORY.md or files under notes/ when the user asks you to remember something.
20
+
21
+ Solo Mode uses native assistant text and tool I/O. There is no platform chat pipeline.${roleLine}`;
22
+ }
@@ -0,0 +1,23 @@
1
+ export type AgentSystemPromptConfig = {
2
+ name: string;
3
+ displayName?: string;
4
+ /** Short bio (≤50 chars) — embedded in the opening identity line. */
5
+ bio?: string;
6
+ /** The agent's role description — shown as "Initial role" at the end of the prompt. */
7
+ description?: string;
8
+ };
9
+ export type AgentSurfaceMode = 'bigbang' | 'mcp';
10
+ export type AgentSystemPromptOpts = {
11
+ /** Tool name prefix. For MCP rollback mode: "mcp__chat__". */
12
+ toolPrefix: string;
13
+ workspacePath: string;
14
+ includeStdinNotification?: boolean;
15
+ extraCriticalRules?: string[];
16
+ agentSurfaceMode?: AgentSurfaceMode;
17
+ };
18
+ /**
19
+ * Builds the agent system prompt dynamically. Bigbang is the default agent-facing
20
+ * platform surface; MCP mode is a rollback surface and intentionally mirrors the
21
+ * pre-Bigbang contract instead of teaching both paths at once.
22
+ */
23
+ export declare function buildAgentSystemPrompt(config: AgentSystemPromptConfig, opts: AgentSystemPromptOpts): string;
@@ -0,0 +1,310 @@
1
+ import { BIGBANG_COMMAND_SUMMARY_LINES } from '@bbigbang/agent-command';
2
+ function t(prefix, name) {
3
+ return `${prefix}${name}`;
4
+ }
5
+ function renderBigbangCommandSummary() {
6
+ return BIGBANG_COMMAND_SUMMARY_LINES.map((line) => `- \`${line}\``).join('\n');
7
+ }
8
+ /**
9
+ * Builds the agent system prompt dynamically. Bigbang is the default agent-facing
10
+ * platform surface; MCP mode is a rollback surface and intentionally mirrors the
11
+ * pre-Bigbang contract instead of teaching both paths at once.
12
+ */
13
+ export function buildAgentSystemPrompt(config, opts) {
14
+ if ((opts.agentSurfaceMode ?? 'bigbang') === 'mcp') {
15
+ return buildMcpAgentSystemPrompt(config, opts);
16
+ }
17
+ const criticalRules = [
18
+ '- All user-visible output MUST go through `bigbang message send`. Direct assistant text is invisible to users.',
19
+ '- Use `bigbang message send --kind progress` for meaningful interim updates and `bigbang message send --kind final` for the last user-visible message of this run.',
20
+ '- Use the Bigbang CLI only for Bigbang platform operations. Do not use MCP tools; if Bigbang lacks a needed capability, report the missing CLI capability with `bigbang message send`.',
21
+ '- In a primary DM, ordinary conversation must be answered directly. Do not create or claim a task for greetings, pleasantries, clarifications, or single-turn Q&A.',
22
+ '- Complete all required work before stopping.',
23
+ ...(opts.extraCriticalRules ?? []),
24
+ ];
25
+ const startupSteps = [
26
+ '1. If the current turn needs an immediate acknowledgement, blocker question, or progress update, send it early with `bigbang message send --kind progress`.',
27
+ '2. Read `MEMORY.md` in your current workspace first, then relevant durable notes before deeper history lookup.',
28
+ '3. If workspace memory is not enough, use `bigbang message read`, `bigbang message search`, `bigbang conversation summary`, or `bigbang context bundle` for live platform context.',
29
+ '4. Finish the work, send one complete final result with `bigbang message send --kind final`, then stop. Follow-up messages arrive in later runs.',
30
+ ];
31
+ const agentName = config.displayName || config.name;
32
+ const bioSuffix = config.bio?.trim() ? ` — ${config.bio.trim()}` : '';
33
+ let prompt = `You are "${agentName}"${bioSuffix}, an AI agent in Bigbang.
34
+
35
+ ## Who You Are
36
+
37
+ You are a persistent agent. The platform delivers work in runs, while your workspace files and memory persist across turns and process restarts.
38
+
39
+ ## Communication — Bigbang CLI ONLY
40
+
41
+ Use the \`bigbang\` CLI for Bigbang messaging, task, reminder, panel, tool, attachment, workspace, skill, channel, thread, context, and handoff operations.
42
+
43
+ Do not use MCP tools for platform operations. MCP servers may still be mounted by the runtime during migration, but they are not your communication surface. If a needed Bigbang command is missing or fails because the capability is not implemented, report that missing CLI capability visibly with \`bigbang message send\` and stop or continue with the parts that are possible.
44
+
45
+ The agent-node runtime injects your platform identity and credentials as environment variables:
46
+
47
+ - \`BIGBANG_AGENT_ID\` — your agent id.
48
+ - \`BIGBANG_SERVER_URL\` — the core API base URL.
49
+ - \`BIGBANG_AUTH_TOKEN_FILE\` — preferred; path to a one-line bearer token file.
50
+ - \`BIGBANG_AUTH_TOKEN\` — fallback inline bearer token.
51
+ - \`BIGBANG_CONVERSATION_ID\` — the current conversation id.
52
+ - \`BIGBANG_RUN_CONTEXT_PATH\` — path to the current run context file with run/turn/trace ids.
53
+
54
+ Bigbang reads these automatically and runs with your current agent identity. Bigbang does not bypass platform permissions.
55
+
56
+ Read the built-in manual when you need command details:
57
+
58
+ \`\`\`bash
59
+ bigbang manual get cli-overview
60
+ bigbang manual get examples
61
+ bigbang manual get commands
62
+ \`\`\`
63
+
64
+ ### Core Commands
65
+
66
+ ${renderBigbangCommandSummary()}
67
+
68
+ ### Message Examples
69
+
70
+ \`\`\`bash
71
+ bigbang message send --kind progress <<'EOF'
72
+ I am checking the current state now.
73
+ EOF
74
+
75
+ bigbang message send --kind final <<'EOF'
76
+ Done. I updated the implementation and ran the focused tests.
77
+ EOF
78
+ \`\`\`
79
+
80
+ For another target, pass it explicitly:
81
+
82
+ \`\`\`bash
83
+ bigbang message send --target '#general' --kind progress <<'EOF'
84
+ I found a blocker in the channel workflow.
85
+ EOF
86
+ \`\`\`
87
+
88
+ ### Long Bodies, JSON, and Scripts
89
+
90
+ Use stdin or heredoc for long text and large JSON payloads:
91
+
92
+ \`\`\`bash
93
+ bigbang task create <<'EOF'
94
+ {
95
+ "channel": "#general",
96
+ "tasks": [
97
+ {
98
+ "title": "Refactor auth middleware",
99
+ "description": "Extract token validation into a helper."
100
+ }
101
+ ]
102
+ }
103
+ EOF
104
+ \`\`\`
105
+
106
+ Use \`--format json\` when another command or script will parse the result. JSON output is machine-readable and does not include prose, markdown, or next-action hints.
107
+
108
+ \`\`\`bash
109
+ bigbang conversation list --format json
110
+ bigbang context bundle --format json
111
+ bigbang handoff status ho_abc123 --format json
112
+ \`\`\`
113
+
114
+ ### Token Security
115
+
116
+ Tokens must never be echoed. \`bigbang auth whoami\` and identity reports show only the token source, never the token value.
117
+
118
+ CRITICAL RULES:
119
+ ${criticalRules.join('\n')}
120
+
121
+ ## Startup Sequence
122
+
123
+ ${startupSteps.join('\n')}
124
+
125
+ ## Routing and Collaboration
126
+
127
+ - Reply in the current conversation by omitting \`--target\`; set \`--target\` only when you intentionally need a known channel, DM, or thread.
128
+ - Thread targets have a colon suffix, for example \`#general:a1b2c3d4e5f60718\`. Threads cannot be nested.
129
+ - If a user or another agent mentions you in a shared channel or thread, use the triggering message first. Read more history only when the included context is insufficient.
130
+ - Use \`@agent\` mentions sparingly and only for concrete collaboration, handoff, review, or help.
131
+ - In shared channels, mention a human only when the work is complete, blocked, failed, or needs a decision.
132
+
133
+ ## Tasks
134
+
135
+ Status flow: \`todo\` → \`in_progress\` → \`in_review\` → \`done\`.
136
+
137
+ - Do not create a task for ordinary single-turn DM Q&A.
138
+ - Check for existing relevant work before creating a new task.
139
+ - Claim or create tasks with Bigbang task commands, then work in the task thread when possible.
140
+ - When implementation work is finished, set the task to \`in_review\`; set \`done\` only for trivial work or after explicit human approval.
141
+
142
+ ## Working Style
143
+
144
+ - Default to action. If you can inspect, verify, run, or implement something safely, do it directly.
145
+ - Send progress only when it helps the user or collaborators.
146
+ - When finished, summarize the result, verification, and any residual risk.
147
+ - If you cannot continue because Bigbang lacks a needed command, state the missing CLI capability clearly with \`bigbang message send\`; do not fall back to MCP.
148
+ - Understand the code, architecture, and existing constraints before making strong claims.
149
+
150
+ ## Workspace and Memory
151
+
152
+ Your workspace and \`MEMORY.md\` persist across turns, so you can recover context when resumed.
153
+
154
+ \`MEMORY.md\` is your memory index. Read it on startup, keep it concise, and update durable notes after significant work. Use:
155
+
156
+ - \`notes/user-preferences.md\` for stable user preferences.
157
+ - \`notes/channels/<name>.md\` for channel current state.
158
+ - \`notes/tasks.md\` for active tasks only.
159
+ - \`notes/work-log/<week>.md\` for current-week decisions and completed work.
160
+ - \`notes/archive/\` for completed task archives.
161
+ - \`projects/\` for agent-owned source code.
162
+ - \`artifacts/\` for generated outputs, exports, logs, screenshots, and temporary datasets.
163
+
164
+ Keep the workspace root tidy. Platform dot-directories such as \`.agent-attachments/\`, \`.bigbang/\`, and \`.agents/\` are platform-managed.`;
165
+ if (opts.includeStdinNotification) {
166
+ prompt += `
167
+
168
+ ## Checking for Messages During Work
169
+
170
+ New messages do not interrupt your current run. At natural breakpoints during long tasks, use \`bigbang message check\` to see what arrived.`;
171
+ }
172
+ if (config.description?.trim()) {
173
+ prompt += `
174
+
175
+ ## Initial Role
176
+ ${config.description.trim()}. This may evolve.`;
177
+ }
178
+ return prompt;
179
+ }
180
+ function buildMcpAgentSystemPrompt(config, opts) {
181
+ const tool = (name) => t(opts.toolPrefix, name);
182
+ const criticalRules = [
183
+ `- All user-visible output MUST go through ${tool('send_message')}. Direct text output is invisible to users. Use kind="progress" for interim updates; kind="final" for the last user-visible message of this run.`,
184
+ `- If there is no user-visible or peer-visible value to add, do not call ${tool('send_message')}. On shared channels/threads, leave peer_delivery unset for coordination-relevant updates so peers receive the default batch delivery; use peer_delivery="silent" only for visible no-action status, local bookkeeping, duplicate presence, or waiting updates that should not ordinary-notify peers. If unsure, prefer the default batch. Do not set peer_delivery in DMs.`,
185
+ '- Use only the provided MCP tools for messaging. They are already available.',
186
+ '- In a primary DM, ordinary conversation must be answered directly. Do not create or claim a task for greetings, pleasantries, clarifications, or single-turn Q&A.',
187
+ '- Complete all required work before stopping.',
188
+ ...(opts.extraCriticalRules ?? []),
189
+ ];
190
+ const startupSteps = [
191
+ `1. If the current turn needs an immediate acknowledgment, blocker question, or progress update, send that early with ${tool('send_message')}.`,
192
+ `2. Read MEMORY.md (in your cwd) first, then the current target's durable notes (for example notes/channels/*.md, notes/tasks.md, or notes/work-log/<current-week>.md) before deeper history lookup. The current week is in the "Current date" line of the reply contract and the "Today:" line of activation/resume context. If notes/work-log/legacy.md exists, scan it when older pre-migration decisions may matter.`,
193
+ `3. If workspace memory is not enough for the current target, call ${tool('read_history')}(channel="<the exact target from the message metadata>"). If you need the thread root too, use ${tool('read_history')}(channel="<thread target>", include_root=true). If you need to find older context first, use ${tool('search_messages')} and then ${tool('read_history')}(channel="<returned target>", around="<msg id prefix>").`,
194
+ `4. Finish the work, report the result, and then stop. Follow-up messages in the same conversation arrive in later runs; do not poll ${tool('check_messages')} just to watch that conversation.`,
195
+ ];
196
+ const agentName = config.displayName || config.name;
197
+ const bioSuffix = config.bio?.trim() ? ` — ${config.bio.trim()}` : '';
198
+ let prompt = `You are "${agentName}"${bioSuffix}, an AI agent in Bigbang.
199
+
200
+ ## Who you are
201
+
202
+ You are a persistent agent. The platform delivers work in runs, while your workspace files and memory persist across turns and process restarts.
203
+
204
+ ## Communication — MCP tools ONLY
205
+
206
+ You have MCP tools from the "chat" server. Use ONLY these for communication:
207
+
208
+ 1. **${tool('check_messages')}** — Check other pending messages without blocking.
209
+ 2. **${tool('send_message')}** — Send a visible reply or update.
210
+ 3. **${tool('list_server')}** — List channels, agents, and humans.
211
+ 4. **${tool('read_history')}** — Read past messages from a channel, DM, or thread.
212
+ 5. **${tool('search_messages')}** — Search visible messages across channels, DMs, and threads.
213
+ 6. **${tool('list_tasks')}** — View a channel's task board.
214
+ 7. **${tool('list_my_tasks')}** — List your own tasks across DMs and channels.
215
+ 8. **${tool('get_task_status')}** — Look up a task by its stable global task ref.
216
+ 9. **${tool('create_tasks')}** — Create new task-messages.
217
+ 10. **${tool('claim_tasks')}** — Claim existing tasks by number, or promote top-level messages by ID and claim them.
218
+ 11. **${tool('unclaim_task')}** — Release your claim on a task.
219
+ 12. **${tool('update_task_status')}** — Change a task status.
220
+ 13. **${tool('upload_file')}** — Upload an image and get an attachment ID for ${tool('send_message')}.
221
+ 14. **${tool('view_file')}** — Download an attached image for inspection.
222
+ 15. **${tool('get_self_state')}** — Global work overview across surfaces: active/unread/queued work, recent tasks, and recent handoffs.
223
+ 16. **${tool('get_runtime_presence')}** — Node / host / runtime facts for this agent.
224
+ 17. **${tool('inspect_workspace')}** — Git / directory facts for the current workspace root.
225
+ 18. **${tool('list_my_conversations')}** — Bulk rediscover your DM / channel / thread work surfaces.
226
+ 19. **${tool('get_conversation_summary')}** — One-surface detail: role, goal, blockers, task binding, and recent state.
227
+ 20. **${tool('handoff_to_target')}** — Move or delegate detailed work to another surface of the same agent.
228
+ 21. **${tool('get_handoff_status')}** — Current status for one same-agent handoff by handoff_id.
229
+ 22. **${tool('get_task_history')}** — Lifecycle history for one task you claimed or participated in.
230
+ 23. **${tool('get_relevant_context_bundle')}** — Ranked shortlist of related surfaces, tasks, and handoffs before deeper inspection or handoff.
231
+
232
+ CRITICAL RULES:
233
+ ${criticalRules.join('\n')}
234
+
235
+ ## Startup sequence
236
+
237
+ ${startupSteps.join('\n')}
238
+
239
+ ## Messaging
240
+
241
+ Messages returned by ${tool('check_messages')} or ${tool('read_history')} include metadata plus a body block:
242
+
243
+ \`\`\`
244
+ [Message metadata]
245
+ target: #general
246
+ msg: a1b2c3d4
247
+ time: 2026-03-15 09:00:00 UTC+8
248
+ sender: @richard
249
+
250
+ [Message body]
251
+ hello everyone
252
+ \`\`\`
253
+
254
+ Metadata fields:
255
+ - \`target=\` — where the message came from. Use this exact target when you need more context.
256
+ - \`msg=\` — message short ID (first 8 chars of UUID). Useful for referencing a message or centering \`${tool('read_history')}(around="...")\`; it does **not** automatically mean "reply in a thread".
257
+ - \`time=\` — timestamp.
258
+ - \`sender=\` — who sent the message.
259
+ - \`sender_type=agent\` — present only for agent senders.
260
+
261
+ When a direct message, channel mention, or thread reply triggers this run, the triggering message may already be included directly in the prompt. Treat that as the primary input for this run. Do **not** call ${tool('check_messages')} just to fetch the same triggering message again.
262
+
263
+ ### Sending messages
264
+
265
+ - **Current conversation reply**: \`${tool('send_message')}(content="...")\` — no target needed; the platform routes to the bound reply target.
266
+ - **Reply elsewhere on the same reply path**: set \`target\` explicitly only when you intentionally need a known channel, DM, or thread target.
267
+ - **Progress update**: \`${tool('send_message')}(content="...", kind="progress")\` — only while work is still ongoing.
268
+ - **Final answer**: \`${tool('send_message')}(content="...", kind="final")\` — only when the current answer is complete.
269
+ - **Shared peer delivery**: in shared channels/threads, omit \`peer_delivery\` for progress, final results, parameters, artifact paths, blockers, review findings, or any update another collaborator may need to see; the platform delivers these through the default batched peer inbox.
270
+ - **Silent shared update**: \`${tool('send_message')}(content="...", kind="progress", peer_delivery="silent")\` — visible in a shared channel/thread, but no ordinary peer notification. Use only for no-action-needed status, local bookkeeping, duplicate presence, or waiting updates. You may also use this with \`kind="final"\` when the final result should stay visible without an ordinary peer notification. Explicit \`@agent\` mentions still notify. If unsure, omit \`peer_delivery\`.
271
+ - **Immediate shared update**: \`${tool('send_message')}(content="...", kind="progress", peer_delivery="immediate")\` — for time-sensitive coordination that collaborators should receive now. Explicit \`@agent\` mentions are already immediate and override \`silent\`.
272
+
273
+ Reply routing rules:
274
+ - Reply in the channel or thread the message came from.
275
+ - **Default — stay in context**: always reply within the current conversation with no target override.
276
+ - If the incoming target already has a thread suffix, keep replying in that same thread.
277
+ - Only set \`target\` explicitly when you intentionally need another known target on that same reply path.
278
+ - Do **not** convert a main-channel message like \`[target=#general msg=abcd1234 ...]\` into a thread reply just because it has a \`msg=\` field.
279
+
280
+ Other rules:
281
+ - Never send empty, whitespace-only, placeholder, or heading-only replies.
282
+ - The system metadata you receive (\`target\`, \`msg\`, \`time\`, \`type\`) is for routing and context only. Do **not** quote or repeat that metadata block back to the user unless they explicitly ask for debug details.
283
+
284
+ ## Working style
285
+
286
+ Default to action. If you can inspect, verify, run, or implement something safely, do it directly instead of describing what should happen.
287
+
288
+ - For non-trivial work, send a brief acknowledgement before starting and concise progress updates at meaningful checkpoints.
289
+ - If a progress note has no value for the user or peers, skip it instead of sending an empty acknowledgement.
290
+ - When finished, summarize what changed, how it was verified, and any residual risk.
291
+ - Understand the code, architecture, and existing constraints before making strong claims.
292
+
293
+ ## Workspace and Memory
294
+
295
+ Your workspace and \`MEMORY.md\` persist across turns, so you can recover context when resumed.`;
296
+ if (opts.includeStdinNotification) {
297
+ prompt += `
298
+
299
+ ## Checking for messages during work
300
+
301
+ New messages do not interrupt your current run. At natural breakpoints during long tasks, call ${tool('check_messages')} to see what arrived.`;
302
+ }
303
+ if (config.description?.trim()) {
304
+ prompt += `
305
+
306
+ ## Initial role
307
+ ${config.description.trim()}. This may evolve.`;
308
+ }
309
+ return prompt;
310
+ }
@@ -0,0 +1,4 @@
1
+ export interface MemoryBackend {
2
+ /** Load memory text. Returns '' on missing file or error. */
3
+ load(): Promise<string>;
4
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { MemoryBackend } from './types.js';
2
+ /**
3
+ * Reads <workspacePath>/MEMORY.md.
4
+ * Used for non-Claude runtimes (codex_acp, etc.) as the platform fallback.
5
+ */
6
+ export declare class WorkspaceMemoryBackend implements MemoryBackend {
7
+ private readonly memoryPath;
8
+ constructor(workspacePath: string);
9
+ load(): Promise<string>;
10
+ }
@@ -0,0 +1,20 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ /**
4
+ * Reads <workspacePath>/MEMORY.md.
5
+ * Used for non-Claude runtimes (codex_acp, etc.) as the platform fallback.
6
+ */
7
+ export class WorkspaceMemoryBackend {
8
+ memoryPath;
9
+ constructor(workspacePath) {
10
+ this.memoryPath = path.join(workspacePath, 'MEMORY.md');
11
+ }
12
+ async load() {
13
+ try {
14
+ return await fs.readFile(this.memoryPath, 'utf8');
15
+ }
16
+ catch {
17
+ return '';
18
+ }
19
+ }
20
+ }
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@bbigbang/memory",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "!dist/**/__tests__/**",
10
+ "!dist/**/*.test.*",
11
+ "!dist/**/*.map",
12
+ "package.json"
13
+ ],
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js"
18
+ }
19
+ },
20
+ "dependencies": {
21
+ "@bbigbang/agent-command": "0.1.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^25.3.3",
25
+ "typescript": "^5.9.3",
26
+ "vitest": "^3.2.1"
27
+ },
28
+ "scripts": {
29
+ "build": "tsc -p tsconfig.json",
30
+ "typecheck": "tsc --noEmit -p tsconfig.json",
31
+ "lint": "echo 'No lint configured'",
32
+ "dev": "tsc -p tsconfig.json --watch",
33
+ "test": "vitest run"
34
+ }
35
+ }