
MemPalace × Antigravity Hook 的 STDIN/STDOUT 线协议事件字段、门控策略与实现剖析【免费下载链接】mempalaceThe best-benchmarked open-source AI memory system. And its free.项目地址: https://gitcode.com/GitHub_Trending/me/mempalace导读本文基于 hooks/antigravity/STDIN_SHAPE.md完整拆解 Google Antigravity IDE 与 MemPalace 生命周期钩子之间的 JSON 线格式wire format契约——包括每次事件都会携带的公共 stdin 字段、Stop/PreInvocation事件的私有字段与 stdout 应答语义以及 save / wake 两个钩子的全部门控条件。读完后你能掌握 Antigravity 插件钩子的调试方法、MemPalace 自动记忆存取的设计约束为何绝不允许输出decision: continue并能直接对照仓库源码逐条理解其 fail-open 的健壮性实现。一、契约总览JSON 进、JSON 出字段一律 camelCaseMemPalace 在 hooks/antigravity/ 下维护了 Antigravity 专用的一套生命周期钩子它是既有 Claude Codehooks/mempal_save_hook.sh与 Cursor 集成的第三位兄弟整体思路一致——Stop事件触发一次后台保存启动期事件向 Agent 注入记忆——但线上格式与 STDOUT 契约是 Antigravity 专属的。Antigravity 的 hook 执行模型非常朴素钩子从stdin接收 JSON并在stdout上回写 JSON字段名使用camelCase钩子默认执行超时为 30 秒。MemPalace 插件在渲染出的hooks.json中把 Stop 钩子超时设为 30s、PreInvocation 钩子超时设为 5s见示例 examples/antigravity/hooks.json。对应地实际安装的插件hooks.json长这样__PLUGIN_DIR__占位符会在安装时被替换为绝对路径见 hooks/antigravity/install.sh 中的模板渲染逻辑{ mempalace-save: { Stop: [ { type: command, command: /ABSOLUTE/PATH/TO/mempalace/hooks/antigravity/mempal_save_hook_antigravity.sh, timeout: 30 } ] }, mempalace-wake: { PreInvocation: [ { type: command, command: /ABSOLUTE/PATH/TO/mempalace/hooks/antigravity/mempal_wake_hook_antigravity.sh, timeout: 5 } ] } }在 hooks/antigravity/INVESTIGATION.md 中可以查到这套字段形状是在 2026-05-27 依据 Google 官方 Antigravity hooks 文档逐一核对的注意PreToolUse/PostToolUse才需要matcher包裹而PreInvocation/Stop是扁平 handler 对象handler 目前只支持command类型timeout单位为秒、缺省 30。二、公共 stdin 字段每一次事件都会携带无论是Stop还是PreInvocation每次事件都带有以下四个公共字段字段类型说明conversationIdstring当前活跃 Agent 会话的 UUID。workspacePathsarraystring绝对路径的工作区目录。数组首个元素被视为规范路径。transcriptPathstringtranscript.jsonl的绝对路径。artifactDirectoryPathstring会话产物与截图所在目录路径。MemPalace 只消费前三个其中workspacePaths[0]被用于推导 wing见下文Wing 推导。这里需要特别强调安全实现钩子收到的每一个字段值都来自 IDE、本质上是用户可控输入因此在 hooks/antigravity/lib/common.sh 的mempal_parse_stdin中Python 解析器会对每个字段做字符集清洗——conversationId只保留[A-Za-z0-9._-]路径类字段只保留安全字符集terminationReason归一为小写字母与下划线整数非法一律回落默认值 0。这样即使某个宿主下发恶意/损坏负载也不可能把 shell 命令注入到任何会被 bash 变量插值的位置。三、Stop 事件会话终结 → 后台记忆保存3.1 事件私有 stdin 字段与 stdout 语义Stop事件在 Agent 执行循环终止时触发除公共字段外还携带字段类型说明executionNuminteger本次会话执行尝试的序号。terminationReasonstring取值如model_stop、max_steps_exceeded、error等。errorstring可选因系统错误而终止时填充。fullyIdleboolean必填。当且仅当所有后台命令与异步任务均已完成时为true。对应的 stdout 应答字段类型说明decisionstring若为continue强制Agent 继续运行其他任何值都放行终止。reasonstring可选当decision continue时会作为一条系统消息注入会话。3.2 红线save 钩子永远只回{}这是本协议中最关键、也最容易被新手踩爆的一条语义约束{decision: continue}会把保存钩子变成永动 Agent的触发器——只要输出一次 continueAgent 就不会结束当前回合进而再次触发 Stop再次 continue……形成无限循环。因此 MemPalace 的策略是save 钩子任何代码路径上都输出{}并以退出码 0 结束绝不构造包含continue字样的 decision 字段。这条约束写死在了两处脚本头注释明确声明NEVER emits{decision: continue}见 mempal_save_hook_antigravity.sh底层mempal_emit_stop_pass硬编码输出字面量{}\n见 lib/common.sh从源头上杜绝任何不小心带出 continue的可能。注意这里的pass与 Claude Code / Cursor 的语义差异Antigravity 把decision之外的所有值包括空对象都解释为允许停止所以{}既是合法输出也是完全无副作用的安全输出。3.3 MemPalace 的十二道门控save 钩子会在下列任意一条成立时短路输出{}不做保存MEMPAL_DISABLE_HOOK1或true/yes已设置MEMPALACE_HOOKS_AUTO_SAVEfalse或0/no已设置~/.mempalace/config.json中hooks.auto_save: false~/.mempalace/目录不存在用户已清空 palacestdin 畸形或为空sentinel 哨兵保护的解析失败fullyIdle false后台任务仍在运行本次暂缓保存terminationReason errortranscript 可能已损坏transcriptPath校验失败不是.json/.jsonl后缀或含..路径穿越transcript 文件在磁盘上不存在保存计数器尚未满足count % MEMPAL_SAVE_INTERVAL 0该会话仍有未完成的保存任务在跑且其标记文件小于 1 小时mempalaceCLI 不在$PATH上。前五项即kill switch组合拳其实现集中在mempal_kill_switch_tripped——它把~/.mempalace/目录被整个删除视为最强信号在触碰任何磁盘状态之前就先行短路而后两项防止污染门控7/8/9与节流门控10/11则是在mempal_save_hook_antigravity.sh主体流程中依次执行的。3.4 命中门控后的真实动作当 modulo 门控命中且全部校验通过时钩子在后台派生一个mempalace mine transcript-dir --mode convos --wing inferred子进程随后立即返回{}。前台返回保持在毫秒级真正的挖掘与向量化全部脱离前台执行绝不阻塞 IDE。从源码看这条路径有几个值得注意的实现取舍mempal_save_hook_antigravity.sh可运行性探测必须放在后台子 shell 里。mempalace --version并不便宜——构建mine参数解析器会先 importmempalace.miner进而拉入 palace → backends → chromadb/onnx一次冷启动 import 可能要数百毫秒若放在前台探测会直接击穿保存钩子毫秒级返回的预算。因此探测、挖掘与清理被整体折叠进同一个后台子 shell。pending 标记先落盘再派生。后台子 shell 结束时rm -f掉 marker若探测失败mempalace不可通过当前解释器运行则在日志中给出ERROR: mempalace is not runnable via ...提示同样清理 marker让下一次 Stop 可以重试。同时有一套1 小时视为陈旧标记并回收的兜底防止崩溃残留把会话永久锁死。调用方式统一为$MEMPAL_PYTHON_BIN -m mempalace而非裸mempalaceconsole script。这样即使用户只在 venv/uv tool install的隔离环境里装了包、其bin/不在钩子进程的PATH上也能命中正确的解释器。这就是 README.md 排障一节所说的MEMPAL_PYTHON_BIN解析顺序$MEMPAL_PYTHON显式覆盖 →mempalace-mcp/mempalaceconsole script 的 shebang 中推导 →PATH上的python3→ 裸python3详见 lib/common.sh 的mempal_resolve_python。四、PreInvocation 事件首次调用前的一次性记忆注入4.1 事件私有 stdin 字段与 stdout 语义PreInvocation在每次模型调用之前触发额外携带字段类型说明invocationNuminteger当前模型调用的序号从 1 开始。initialNumStepsinteger轨迹trajectory中当前已有的步数。stdout 只允许一类可选字段字段类型说明injectStepsarrayobject在模型被调用前注入的步骤。每步取三种形态之一{toolCall: {...}}、{userMessage: ...}、{ephemeralMessage: ...}。ephemeralMessage形态正是 MemPalace wake 钩子所用的注入通道唤醒文本在本回合对模型可见但不会持久化进 transcript因此后续的模型调用不会看到重复注入。4.2 MemPalace 的四道门控wake 钩子会在以下任意条件成立时短路输出{}不注入任一 kill switch 被触发与 save 钩子相同的五个条件invocationNum ! 1——只在每个会话的第一次模型调用时注入模拟 Cursor 的sessionStart语义基于原子mkdir的循环守卫已被占用说明该会话已经收过一次唤醒注入mempalace wake-up --wing inferred非零退出、超时500ms 硬上限或产生空输出。4.3 通过门控后的输出形态门控通过且mempalace wake-up返回了文本时钩子输出{ injectSteps: [ { ephemeralMessage: wake-up 输出逐字原文 } ] }与 save 钩子对称地wake 钩子还有一条反向红线绝不输出decision字段——那是 Stop 事件的私有字段。脚本在输出前对 stdout 做最后一道case检查一旦发现任何含decision键的内容就拒绝下发并回退为{}见 mempal_wake_hook_antigravity.sh。4.4 源码层面的健壮性细节500ms 硬超时集成约定给启动注入的预算是 100ms而实现放宽到 500ms理由是冷启动时 ChromaDB 连接耗时可能占大头——错过预算比阻塞用户更好。超时探测没有用 GNUtimeoutmacOS 缺省不带而是用subprocess.run(timeout0.5)实现跨平台超时见 wake 钩子内嵌的 Python 片段。原子 mkdir 守卫antigravity_woke_conversationId目录用mkdir创建——mkdir 原子且不依赖 flock 等 GNU 扩展在 bash 3.2 / macOS / Linux 上都可用目录已存在即视为本次会话已唤醒过。逐字保证ephemeralMessage携带mempalace wake-up输出的精确原文绝不转述或摘要JSON 转义交给json.dumps统一处理。五、完整 Worked ExamplesSTDIN_SHAPE.md 给出了两个可直接当作契约测试夹具的完整示例。5.1 Stop 事件输入某次model_stop终止、后台完全空闲{ executionNum: 1, terminationReason: model_stop, error: , fullyIdle: true, conversationId: ec33ebf9-0cba-4100-8142-c61503f6c587, workspacePaths: [/home/me/projects/mempalace], transcriptPath: /home/me/projects/mempalace/.gemini/jetski/transcript.jsonl, artifactDirectoryPath: /home/me/projects/mempalace/.gemini/jetski/artifacts }输出恒定{}副作用计数器文件~/.mempalace/hook_state/antigravity_save_count_id被递增若 modulo 门控命中后台mempalace mine子进程会以 transcript 目录和推导出的 wing本例为wing_mempalace被派生。5.2 PreInvocation 事件首次调用输入{ invocationNum: 1, initialNumSteps: 0, conversationId: ec33ebf9-0cba-4100-8142-c61503f6c587, workspacePaths: [/home/me/projects/mempalace], transcriptPath: /home/me/projects/mempalace/.gemini/jetski/transcript.jsonl, artifactDirectoryPath: /home/me/projects/mempalace/.gemini/jetski/artifacts }输出 Apalace 中已有wing_mempalace的记忆{ injectSteps: [ { ephemeralMessage: 来自 mempalace wake-up --wing wing_mempalace 的逐字原文 } ] }输出 BinvocationNum ! 1或任一门控触发{}六、状态文件全部状态收敛到hook_state/所有钩子状态统一存放于~/.mempalace/hook_state/可用$MEMPAL_STATE_DIR覆盖并使用antigravity_前缀做命名空间隔离以便与 Claude Code、Cursor、Codex 的钩子状态在同一目录下共存文件用途antigravity_hook.log全部钩子活动日志ISO8601Z 时间戳。antigravity_save_count_conversationId每个会话的 Stop 计数器。antigravity_pending_conversationId正在进行的保存子进程的标记文件。antigravity_woke_conversationId目录原子 mkdir 唤醒注入标记。antigravity_last_input.log4KB 上限、0600 权限解析失败时落盘的原始输入。antigravity_last_python_err.logJSON 解析器Python的 stderr0600 权限。实现层面的两个细节值得一提lib/common.sh计数器原子写mempal_write_counter_atomic用同目录临时文件 mv实现原子重命名并发读者要么看到旧值要么看到新值绝不看到半截内容读侧还做纯整数校验任何乱码值都会把计数重置为 0。陈旧状态自动 GCmempal_gc_stale_state以MEMPAL_STATE_TTL_DAYS默认 30 天0 表示激进清扫为 TTL用三条名称模式antigravity_save_count_*、antigravity_pending_*、antigravity_woke_*精准清除每会话状态且通过antigravity_last_sweep标记把清扫频率限制为最多每 24h 一次——绝大多数触发只付出一次 mtime 比较的成本。七、环境变量速查变量默认值用途MEMPAL_PYTHON$(command -v python3)覆盖钩子使用的 Python 解释器。MEMPAL_STATE_DIR~/.mempalace/hook_state覆盖钩子状态目录。MEMPAL_SAVE_INTERVAL15每第 N 次 Stop 触发一次保存下限钳制为 1杜绝除零。MEMPAL_DISABLE_HOOK未设置设为1/true/yes同时禁用两个钩子。MEMPALACE_HOOKS_AUTO_SAVE未设置设为false/0/no同时禁用两个钩子。其中MEMPAL_SAVE_INTERVAL的处理在 lib/common.sh 的mempal_save_interval中额外防御了两类边界空值/非数字回落 15前导零如08会被剥离避免 bash 把$((...))中的08当八进制解析而报 value too great for base。八、与 Cursor/Claude Code 钩子协议的差异速览同样承载停止时保存、启动时注入但三家 IDE 的线格式与语义各不同。Antigravity 版的关键差异是维度Antigravity本文Cursorhooks/cursor/STDIN_SHAPE.md字段命名camelCasesnake_caseconversation_id等Stop 输出只能{}decision: continue会触发无限循环允许followup_message自动续接启动注入点PreInvocationinvocationNum 1门控专门的sessionStart事件注入通道injectSteps[].ephemeralMessage不落 transcriptadditional_context写入初始系统上下文Claude Code 版可对照 hooks/mempal_save_hook.sh 查看 snake_case 的session_id/transcript_path/stop_hook_active形态。正是这些差异让 lib/common.sh 选择了sentinel 逐行 sed 取值的解析模式它不依赖mapfile/readarray/declare -A在 bash 3.2macOS 默认上同样成立天然适配各家不同字段布局。九、排障要诀钩子根本没触发打开 Antigravity 的 Customizations 页确认mempalace出现在全局插件列表随后检查~/.mempalace/hook_state/antigravity_hook.log——每次触发都会落一行无日志即未被调用。也可bash -n检查渲染后脚本语法。保存计数在走但从不挖掘在antigravity_hook.log中找最新的[eventstop]行确认count与interval均可见——挖掘仅在count % interval 0时触发。若出现ERROR: mempalace is not runnable ...说明当前解析出的 Python 无法 import mempalaceGUI 启动的 Antigravity 其PATH往往与你的 shell 不同此时应显式export MEMPAL_PYTHON/abs/path/python例如$(uv tool dir)/mempalace/bin/python后重启。唤醒注入始终不出现先确认invocationNum 1门控是否满足再检查唤醒标记目录antigravity_woke_conversationId是否已存在已存在即本次会话已注入过可手动移除以便复现属罕见操作最后mempalace status确认对应 wing 已存在——wing 尚不存在时wake-up会返回空输出钩子按门控规则安全跳过。完整的分步排查清单见 hooks/antigravity/README.md。安装含--dry-run、--install-dir、--uninstall与 workspace 级安装说明同样在 hooks/antigravity/README.md面向终端用户的整体指南位于 website/guide/antigravity.md插件样例可对照 examples/antigravity/。字段真实性审计与为何未随附某些表面PreCompact 订阅、rules、权限声明等的设计决策记录在 hooks/antigravity/INVESTIGATION.md。【免费下载链接】mempalaceThe best-benchmarked open-source AI memory system. And its free.项目地址: https://gitcode.com/GitHub_Trending/me/mempalace创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考