mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(gateway): stop showing retired HEARTBEAT.md in the agent files editor (#113621)
* fix(gateway): drop retired HEARTBEAT.md from agent core files * fix(ci): stop asserting retired HEARTBEAT.md in docker release smoke * docs: align HEARTBEAT.md references with cron scratch * docs(agents): drop retired HEARTBEAT.md from workspace read comment
This commit is contained in:
committed by
GitHub
parent
591e029095
commit
f43fac21c7
@@ -359,7 +359,6 @@ jobs:
|
||||
cat "${temp_root}/out.log"
|
||||
exit 1
|
||||
fi
|
||||
test -f "${temp_root}/home/.openclaw/workspace/HEARTBEAT.md"
|
||||
if [ "${status}" -ne 0 ]; then
|
||||
cat "${temp_root}/out.log"
|
||||
fi
|
||||
@@ -568,7 +567,6 @@ jobs:
|
||||
cat "${temp_root}/out.log"
|
||||
exit 1
|
||||
fi
|
||||
test -f "${temp_root}/home/.openclaw/workspace/HEARTBEAT.md"
|
||||
if [ "${status}" -ne 0 ]; then
|
||||
cat "${temp_root}/out.log"
|
||||
fi
|
||||
|
||||
@@ -1634,5 +1634,13 @@
|
||||
{
|
||||
"source": "Gateway security",
|
||||
"target": "Gateway 安全"
|
||||
},
|
||||
{
|
||||
"source": "Retired HEARTBEAT.md workspace file",
|
||||
"target": "已弃用的 HEARTBEAT.md 工作区文件"
|
||||
},
|
||||
{
|
||||
"source": "Cron CLI",
|
||||
"target": "Cron CLI"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -259,7 +259,7 @@ Extracts the last user/assistant messages (default 15, configurable with `hooks.
|
||||
}
|
||||
```
|
||||
|
||||
`patterns` and `files` are accepted as aliases of `paths`. Paths resolve relative to the workspace and must stay inside it. Only recognized bootstrap basenames are loaded (`AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`, `MEMORY.md`).
|
||||
`patterns` and `files` are accepted as aliases of `paths`. Paths resolve relative to the workspace and must stay inside it. Only recognized bootstrap basenames are loaded (`AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `BOOTSTRAP.md`, `MEMORY.md`).
|
||||
|
||||
<a id="command-logger"></a>
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ Each program specifies:
|
||||
The agent loads these instructions every session via the workspace bootstrap files (see [Agent Workspace](/concepts/agent-workspace) for the full list of auto-injected files) and executes against them, combined with [cron jobs](/automation/cron-jobs) for time-based enforcement.
|
||||
|
||||
<Tip>
|
||||
Put standing orders in `AGENTS.md` to guarantee they're loaded every session. The workspace bootstrap automatically injects `AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`, and `MEMORY.md` - but not arbitrary files in subdirectories.
|
||||
Put standing orders in `AGENTS.md` to guarantee they're loaded every session. The workspace bootstrap automatically injects `AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `BOOTSTRAP.md`, and `MEMORY.md` - but not arbitrary files in subdirectories.
|
||||
</Tip>
|
||||
|
||||
## Anatomy of a standing order
|
||||
|
||||
+1
-1
@@ -291,7 +291,7 @@ openclaw onboard --non-interactive \
|
||||
- Unless you pass `--skip-health`, onboarding waits for a reachable local gateway before exiting successfully.
|
||||
- `--install-daemon` starts the managed gateway install path first. Without it, a local gateway must already be running (for example `openclaw gateway run`).
|
||||
- `--skip-health` skips the wait if you only want config/workspace/bootstrap writes in automation.
|
||||
- `--skip-bootstrap` sets `agents.defaults.skipBootstrap: true` and skips creating `AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, and `BOOTSTRAP.md`.
|
||||
- `--skip-bootstrap` sets `agents.defaults.skipBootstrap: true` and skips creating `AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, and `BOOTSTRAP.md`.
|
||||
- On native Windows, `--install-daemon` tries Scheduled Tasks first and falls back to a per-user Startup-folder login item if task creation is denied.
|
||||
|
||||
### Interactive ref mode
|
||||
|
||||
@@ -79,9 +79,6 @@ Standard files OpenClaw expects inside the workspace:
|
||||
<Accordion title="TOOLS.md - local tool conventions">
|
||||
Notes about your local tools and conventions. Does not control tool availability; it is only guidance.
|
||||
</Accordion>
|
||||
<Accordion title="HEARTBEAT.md - heartbeat checklist">
|
||||
Optional tiny checklist for heartbeat runs. Keep it short to avoid token burn.
|
||||
</Accordion>
|
||||
<Accordion title="BOOT.md - startup checklist">
|
||||
Optional startup checklist run automatically on gateway restart (when [internal hooks](/automation/hooks) are enabled). Keep it short; use the message tool for outbound sends.
|
||||
</Accordion>
|
||||
@@ -140,7 +137,7 @@ Run these steps on the machine where the Gateway runs (that is where the workspa
|
||||
```bash
|
||||
cd ~/.openclaw/workspace
|
||||
git init
|
||||
git add AGENTS.md SOUL.md TOOLS.md IDENTITY.md USER.md HEARTBEAT.md memory/
|
||||
git add AGENTS.md SOUL.md TOOLS.md IDENTITY.md USER.md memory/
|
||||
git commit -m "Add agent workspace"
|
||||
```
|
||||
|
||||
@@ -238,7 +235,7 @@ Suggested `.gitignore` starter:
|
||||
|
||||
## Related
|
||||
|
||||
- [Heartbeat](/gateway/heartbeat) - HEARTBEAT.md workspace file
|
||||
- [Heartbeat](/gateway/heartbeat) - heartbeat monitors and cron scratch
|
||||
- [Sandboxing](/gateway/sandboxing) - workspace access in sandboxed environments
|
||||
- [Session](/concepts/session) - session storage paths
|
||||
- [Standing orders](/automation/standing-orders) - persistent instructions in workspace files
|
||||
|
||||
@@ -37,7 +37,6 @@ Inside the workspace, OpenClaw expects these user-editable files:
|
||||
| `TOOLS.md` | User-maintained tool notes and conventions |
|
||||
| `IDENTITY.md` | Agent name/vibe/emoji |
|
||||
| `USER.md` | User profile + preferred address |
|
||||
| `HEARTBEAT.md` | Heartbeat-specific instructions |
|
||||
| `BOOTSTRAP.md` | One-time first-run ritual (deleted after completion) |
|
||||
| `MEMORY.md` | Root long-term memory file, if present |
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ Injected workspace files:
|
||||
- TOOLS.md: TRUNCATED | raw 54,210 chars (~13,553 tok) | injected 20,962 chars (~5,241 tok)
|
||||
- IDENTITY.md: OK | raw 211 chars (~53 tok) | injected 211 chars (~53 tok)
|
||||
- USER.md: OK | raw 388 chars (~97 tok) | injected 388 chars (~97 tok)
|
||||
- HEARTBEAT.md: MISSING | raw 0 | injected 0
|
||||
- BOOTSTRAP.md: OK | raw 0 chars (~0 tok) | injected 0 chars (~0 tok)
|
||||
|
||||
Skills list (system prompt text): 2,184 chars (~546 tok) (12 skills)
|
||||
@@ -122,7 +121,6 @@ By default, OpenClaw injects a fixed set of workspace files (if present):
|
||||
- `TOOLS.md`
|
||||
- `IDENTITY.md`
|
||||
- `USER.md`
|
||||
- `HEARTBEAT.md`
|
||||
- `BOOTSTRAP.md` (first-run only)
|
||||
|
||||
Large files are truncated per-file using `agents.defaults.bootstrapMaxChars` (default `20000` chars). OpenClaw also enforces a total bootstrap injection cap across files with `agents.defaults.bootstrapTotalMaxChars` (default `60000` chars). `/context` shows **raw vs injected** sizes and whether truncation happened.
|
||||
|
||||
@@ -94,13 +94,12 @@ Bootstrap files are resolved from the active workspace and routed to the prompt
|
||||
- `TOOLS.md`
|
||||
- `IDENTITY.md`
|
||||
- `USER.md`
|
||||
- `HEARTBEAT.md`
|
||||
- `BOOTSTRAP.md` (only on brand-new workspaces)
|
||||
- `MEMORY.md` when present
|
||||
|
||||
On the native Codex harness, OpenClaw avoids repeating stable workspace files in every user turn. Codex loads `AGENTS.md` through its own project-doc discovery. `TOOLS.md` is forwarded as inherited Codex developer instructions. `SOUL.md`, `IDENTITY.md`, and `USER.md` are forwarded as turn-scoped collaboration developer instructions so native Codex sub-agents do not inherit them. `HEARTBEAT.md` content is not injected directly; heartbeat turns get a collaboration-mode note pointing to the file when it exists and is non-empty. `MEMORY.md` content is not pasted into every native Codex turn either: when memory tools are available for the workspace, Codex turns get a small workspace-memory note directing the model to `memory_search` or `memory_get`. If tools are disabled, memory search is unavailable, or the active workspace differs from the agent memory workspace, `MEMORY.md` falls back to the normal bounded turn-context path. `BOOTSTRAP.md` keeps the normal turn-context role.
|
||||
On the native Codex harness, OpenClaw avoids repeating stable workspace files in every user turn. Codex loads `AGENTS.md` through its own project-doc discovery. `TOOLS.md` is forwarded as inherited Codex developer instructions. `SOUL.md`, `IDENTITY.md`, and `USER.md` are forwarded as turn-scoped collaboration developer instructions so native Codex sub-agents do not inherit them. `MEMORY.md` content is not pasted into every native Codex turn either: when memory tools are available for the workspace, Codex turns get a small workspace-memory note directing the model to `memory_search` or `memory_get`. If tools are disabled, memory search is unavailable, or the active workspace differs from the agent memory workspace, `MEMORY.md` falls back to the normal bounded turn-context path. `BOOTSTRAP.md` keeps the normal turn-context role.
|
||||
|
||||
On non-Codex harnesses, bootstrap files compose into the OpenClaw prompt per their existing gates. `HEARTBEAT.md` is omitted on normal runs when heartbeats are disabled for the default agent or `agents.defaults.heartbeat.includeSystemPromptSection` is false. Keep injected files concise, especially non-Codex `MEMORY.md`: it should stay a curated long-term summary, with detailed daily notes in `memory/*.md` retrievable on demand via `memory_search` / `memory_get`. Oversized non-Codex `MEMORY.md` files increase prompt usage and can be partially injected under the bootstrap file limits below.
|
||||
On non-Codex harnesses, bootstrap files compose into the OpenClaw prompt per their existing gates. Keep injected files concise, especially non-Codex `MEMORY.md`: it should stay a curated long-term summary, with detailed daily notes in `memory/*.md` retrievable on demand via `memory_search` / `memory_get`. Oversized non-Codex `MEMORY.md` files increase prompt usage and can be partially injected under the bootstrap file limits below.
|
||||
|
||||
<Note>
|
||||
`memory/*.md` daily files are **not** part of the normal bootstrap Project Context. On ordinary turns they are accessed on demand via `memory_search` / `memory_get`, so they do not count against the context window unless the model explicitly reads them. Bare `/new` and `/reset` turns are the exception: the runtime can prepend recent daily memory as a one-shot startup-context block for that first turn.
|
||||
|
||||
+1
-1
@@ -9057,7 +9057,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
|
||||
|
||||
- Route: /reference/templates/HEARTBEAT
|
||||
- Headings:
|
||||
- H1: HEARTBEAT.md template
|
||||
- H1: HEARTBEAT.md is retired
|
||||
- H2: Related
|
||||
|
||||
## reference/templates/IDENTITY.dev.md
|
||||
|
||||
+2
-2
@@ -477,7 +477,7 @@ First-run Q&A - install, onboard, auth routes, subscriptions, initial failures -
|
||||
<Accordion title="Where should AGENTS.md / SOUL.md / USER.md / MEMORY.md live?">
|
||||
These live in the **agent workspace**, not `~/.openclaw`.
|
||||
|
||||
- **Workspace (per agent)**: `AGENTS.md`, `SOUL.md`, `IDENTITY.md`, `USER.md`, `MEMORY.md`, `memory/YYYY-MM-DD.md`, optional `HEARTBEAT.md`. Lowercase root `memory.md` is legacy repair input only; `openclaw doctor --fix` can merge it into `MEMORY.md` when both exist.
|
||||
- **Workspace (per agent)**: `AGENTS.md`, `SOUL.md`, `IDENTITY.md`, `USER.md`, `MEMORY.md`, `memory/YYYY-MM-DD.md`. Lowercase root `memory.md` is legacy repair input only; `openclaw doctor --fix` can merge it into `MEMORY.md` when both exist.
|
||||
- **State dir (`~/.openclaw`)**: config, channel/provider state, auth profiles, sessions, logs, shared skills (`~/.openclaw/skills`).
|
||||
|
||||
Default workspace is `~/.openclaw/workspace`, configurable:
|
||||
@@ -1036,7 +1036,7 @@ First-run Q&A - install, onboard, auth routes, subscriptions, initial failures -
|
||||
}
|
||||
```
|
||||
|
||||
If `HEARTBEAT.md` exists but is effectively empty (only blank lines, Markdown/HTML comments, ATX headings, fence markers, or empty list-item stubs), OpenClaw skips the heartbeat run to save API calls. If the file is missing, the heartbeat still runs and the model decides what to do.
|
||||
Heartbeat instructions live in the monitor's cron scratch. Effectively empty scratch skips the heartbeat run to save API calls; without scratch, the heartbeat still runs and the model decides what to do.
|
||||
|
||||
Per-agent overrides use `agents.entries.*.heartbeat`. Docs: [Heartbeat](/gateway/heartbeat).
|
||||
|
||||
|
||||
@@ -685,9 +685,9 @@ bootstrap files as developer instructions, but not identically:
|
||||
- The compact loaded OpenClaw skills list is also forwarded as turn-scoped
|
||||
collaboration developer instructions, so native Codex subagents do not
|
||||
inherit it either.
|
||||
- `HEARTBEAT.md` content is not injected; heartbeat turns get a
|
||||
collaboration-mode pointer to read the file when it exists and is
|
||||
non-empty.
|
||||
- Heartbeat turns receive generic initiative guidance through collaboration
|
||||
mode. Monitor cron scratch is appended to the heartbeat prompt instead of
|
||||
injected as workspace context.
|
||||
- `MEMORY.md` content from the configured agent workspace is not pasted into
|
||||
native Codex turn input when memory tools are available for that
|
||||
workspace; when it exists, the harness adds a small workspace-memory
|
||||
|
||||
@@ -124,8 +124,8 @@ Codex heartbeat turns get `heartbeat_respond` in the searchable OpenClaw tool
|
||||
catalog by default so the agent can record whether the wake should stay quiet
|
||||
or notify. Heartbeat initiative guidance is sent as a Codex collaboration-mode
|
||||
developer instruction scoped to the heartbeat turn; ordinary chat turns stay
|
||||
in Codex Default mode. When `HEARTBEAT.md` is non-empty, the heartbeat
|
||||
instructions point Codex at the file instead of inlining its contents.
|
||||
in Codex Default mode. The heartbeat monitor's cron scratch is appended to the
|
||||
heartbeat prompt when present.
|
||||
|
||||
## Hook boundaries
|
||||
|
||||
|
||||
@@ -129,11 +129,11 @@ If a provider does not support any of the above cache modes, `cacheRetention` ha
|
||||
|
||||
## System-prompt cache boundary
|
||||
|
||||
OpenClaw splits the system prompt into a **stable prefix** and a **volatile suffix** at an internal cache-prefix boundary. Content above the boundary (tool definitions, skills metadata, workspace files) is ordered to stay byte-identical across turns. Content below the boundary (for example `HEARTBEAT.md`, runtime timestamps, other per-turn metadata) can change without invalidating the cached prefix.
|
||||
OpenClaw splits the system prompt into a **stable prefix** and a **volatile suffix** at an internal cache-prefix boundary. Content above the boundary (tool definitions, skills metadata, workspace files) is ordered to stay byte-identical across turns. Content below the boundary (for example runtime timestamps and other per-turn metadata) can change without invalidating the cached prefix.
|
||||
|
||||
Key design choices:
|
||||
|
||||
- Stable workspace project-context files are ordered before `HEARTBEAT.md` so heartbeat churn does not bust the stable prefix.
|
||||
- Stable workspace project-context files are ordered before volatile per-turn metadata so routine churn does not bust the stable prefix.
|
||||
- The boundary applies across Anthropic-family, OpenAI-family, Google, and CLI transport shaping, so all supported providers benefit from the same prefix stability.
|
||||
- Codex Responses and Anthropic Vertex requests are routed through boundary-aware cache shaping so cache reuse stays aligned with what providers actually receive.
|
||||
- System-prompt fingerprints are normalized (whitespace, line endings, hook-added context, runtime capability ordering) so semantically unchanged prompts share cache across turns.
|
||||
|
||||
@@ -51,7 +51,7 @@ Before proposing or building a custom system, feature, workflow, tool, integrati
|
||||
|
||||
## Heartbeats (optional)
|
||||
|
||||
- HEARTBEAT.md can hold a tiny checklist for heartbeat runs; keep it small.
|
||||
- The heartbeat monitor's cron scratch can hold a tiny checklist for heartbeat runs; keep it small.
|
||||
|
||||
## Customize
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ Skills provide your tools. When you need one, check its `SKILL.md`. Keep local n
|
||||
|
||||
## Heartbeats - Be Proactive
|
||||
|
||||
When you receive a heartbeat poll (message matches the configured heartbeat prompt), don't just reply `HEARTBEAT_OK` every time. You're free to edit `HEARTBEAT.md` with a short checklist or reminders - keep it small to limit token burn.
|
||||
When you receive a heartbeat poll (message matches the configured heartbeat prompt), don't just reply `HEARTBEAT_OK` every time. Keep a short checklist or reminders in the heartbeat monitor's cron scratch; use `openclaw cron list --all` to find the monitor job, then `openclaw cron scratch <jobId> --set "..."` to update it. Keep it small to limit token burn.
|
||||
|
||||
See [Scheduled Tasks (Cron) vs Heartbeat](/automation#scheduled-tasks-cron-vs-heartbeat) for the full decision table. Short version: heartbeat batches periodic checks with full session context on approximate timing (default every 30 minutes); cron is for exact timing, isolated runs, a different model, or one-shot reminders.
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ read_when:
|
||||
|
||||
_You just woke up. Keep this first conversation short and make it yours._
|
||||
|
||||
OpenClaw only seeds this file into a brand-new workspace, alongside `AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, and `HEARTBEAT.md`. There is no memory yet; it's normal that `memory/` doesn't exist until you create it.
|
||||
OpenClaw only seeds this file into a brand-new workspace, alongside `AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, and `USER.md`. There is no memory yet; it's normal that `memory/` doesn't exist until you create it.
|
||||
|
||||
Complete these three beats. Do not turn them into a questionnaire or a long
|
||||
biography.
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
---
|
||||
summary: "Workspace template for HEARTBEAT.md"
|
||||
title: "HEARTBEAT.md template"
|
||||
summary: "Migration guide for the retired HEARTBEAT.md workspace file"
|
||||
title: "Retired HEARTBEAT.md workspace file"
|
||||
read_when:
|
||||
- Bootstrapping a workspace manually
|
||||
- Migrating an older workspace that still has HEARTBEAT.md
|
||||
---
|
||||
|
||||
# HEARTBEAT.md template
|
||||
# HEARTBEAT.md is retired
|
||||
|
||||
`HEARTBEAT.md` lives in the agent workspace and holds the periodic heartbeat checklist. Keep it empty, or with only whitespace, Markdown comments, ATX headings, empty list stubs (`- `, `* [ ]`), or fence markers, to make OpenClaw skip the heartbeat model call entirely (`reason=empty-heartbeat-file`).
|
||||
OpenClaw no longer creates `HEARTBEAT.md` in new workspaces or reads it at runtime. Heartbeat instructions now live in the system-owned monitor's cron scratch in the shared state database.
|
||||
|
||||
Shipped default content:
|
||||
Manage the current scratch with the monitor job id from `openclaw cron list --all`:
|
||||
|
||||
```markdown
|
||||
<!-- Heartbeat template; comments-only content prevents scheduled heartbeat API calls. -->
|
||||
|
||||
# Keep this file empty (or with only comments) to skip heartbeat API calls.
|
||||
|
||||
# Add a short checklist below when the heartbeat should inspect shared context.
|
||||
```bash
|
||||
openclaw cron scratch <jobId>
|
||||
openclaw cron scratch <jobId> --set "..."
|
||||
openclaw cron scratch <jobId> --file notes.md
|
||||
openclaw cron scratch <jobId> --unset
|
||||
```
|
||||
|
||||
Add a short checklist below the comment lines only when one heartbeat turn should inspect the items together. Keep it small: heartbeat runs read this file every tick (default every 30 minutes), so bloated instructions burn tokens on every wake.
|
||||
|
||||
For independently scheduled or due-only checks, create [cron jobs](/automation/cron-jobs). Heartbeat scratch no longer supports scheduler syntax. Run `openclaw doctor --fix` to convert older `tasks:` blocks.
|
||||
If an older workspace still contains `HEARTBEAT.md`, run `openclaw doctor --fix`. Doctor imports its instructions into monitor scratch, converts valid legacy `tasks:` entries into cron jobs, archives the original under the state directory, and removes the workspace file.
|
||||
|
||||
## Related
|
||||
|
||||
- [Heartbeat](/gateway/heartbeat)
|
||||
- [Cron CLI](/cli/cron)
|
||||
- [Doctor](/cli/doctor)
|
||||
- [Heartbeat config](/gateway/config-agents)
|
||||
|
||||
@@ -21,7 +21,7 @@ OpenClaw assembles its own system prompt on every run. It includes:
|
||||
override at `agents.entries.*.skillsLimits.maxSkillsPromptChars`.
|
||||
- Self-update instructions
|
||||
- Workspace + bootstrap files (`AGENTS.md`, `SOUL.md`, `TOOLS.md`,
|
||||
`IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md` when new, plus
|
||||
`IDENTITY.md`, `USER.md`, `BOOTSTRAP.md` when new, plus
|
||||
`MEMORY.md` when present). Large injected files are truncated by
|
||||
`agents.defaults.bootstrapMaxChars` (default: `20000`); total bootstrap
|
||||
injection is capped by `agents.defaults.bootstrapTotalMaxChars` (default:
|
||||
|
||||
@@ -17,7 +17,7 @@ onboarding, on the agent's first real turn.
|
||||
On the first run against a brand-new workspace (default `~/.openclaw/workspace`),
|
||||
OpenClaw:
|
||||
|
||||
- Seeds `AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, and `BOOTSTRAP.md`.
|
||||
- Seeds `AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, and `BOOTSTRAP.md`.
|
||||
- Has the agent follow a capped three-beat birth sequence: it asks what you want
|
||||
to call it, shares one short soul/vibe line, and asks whether you want the
|
||||
minimal recommended plugin set or maximum convenience.
|
||||
|
||||
+1
-1
@@ -180,7 +180,7 @@ Use these hubs to discover every page, including deep dives and reference docs t
|
||||
- [Default AGENTS](/reference/AGENTS.default)
|
||||
- [Templates: AGENTS](/reference/templates/AGENTS)
|
||||
- [Templates: BOOTSTRAP](/reference/templates/BOOTSTRAP)
|
||||
- [Templates: HEARTBEAT](/reference/templates/HEARTBEAT)
|
||||
- [Retired HEARTBEAT.md workspace file](/reference/templates/HEARTBEAT)
|
||||
- [Templates: IDENTITY](/reference/templates/IDENTITY)
|
||||
- [Templates: SOUL](/reference/templates/SOUL)
|
||||
- [Templates: TOOLS](/reference/templates/TOOLS)
|
||||
|
||||
@@ -674,7 +674,7 @@ still need normal device approval for scope upgrades.
|
||||
- Sub-agent announce is **best-effort**. If the gateway restarts, pending "announce back" work is lost.
|
||||
- Sub-agents still share the same gateway process resources; treat `maxConcurrent` as a safety valve.
|
||||
- `sessions_spawn` is always non-blocking: it returns `{ status: "accepted", runId, childSessionKey }` immediately.
|
||||
- Sub-agent context only injects `AGENTS.md` and `TOOLS.md` (no `SOUL.md`, `IDENTITY.md`, `USER.md`, `MEMORY.md`, `HEARTBEAT.md`, or `BOOTSTRAP.md`). Codex-native subagents follow the same boundary: `TOOLS.md` stays in inherited Codex thread instructions, while parent-only persona, identity, and user files are injected as turn-scoped collaboration instructions so children do not clone them.
|
||||
- Sub-agent context only injects `AGENTS.md` and `TOOLS.md` (no `SOUL.md`, `IDENTITY.md`, `USER.md`, `MEMORY.md`, or `BOOTSTRAP.md`). Codex-native subagents follow the same boundary: `TOOLS.md` stays in inherited Codex thread instructions, while parent-only persona, identity, and user files are injected as turn-scoped collaboration instructions so children do not clone them.
|
||||
- Maximum nesting depth is 5 (`maxSpawnDepth` range: 1-5). Depth 2 is recommended for most use cases.
|
||||
- `maxChildrenPerAgent` caps active children per session (default `5`, range `1-20`).
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ scenario:
|
||||
config:
|
||||
prompt: |-
|
||||
Subagent fanout synthesis check: delegate exactly two bounded subagents sequentially using sessions_spawn, not ACP.
|
||||
First spawn exactly one child with label qa-fanout-alpha and task: verify that `HEARTBEAT.md` exists and reply exactly `ok` if it does. Wait for that child to finish.
|
||||
First spawn exactly one child with label qa-fanout-alpha and task: verify that `AGENTS.md` exists and reply exactly `ok` if it does. Wait for that child to finish.
|
||||
Then spawn exactly one child with label qa-fanout-beta and task: verify that `repo/qa/scenarios/agents/subagent-fanout-synthesis.yaml` exists and reply exactly `ok` if it does. Wait for that child to finish.
|
||||
Do not spawn any more children after qa-fanout-beta finishes.
|
||||
Then reply with exactly these two lines and nothing else:
|
||||
@@ -89,7 +89,7 @@ flow:
|
||||
expr: "env.providerMode === 'mock-openai' ? config.expectedChildLabels[1] : `${config.expectedChildLabels[1]}-${attempt}`"
|
||||
- set: prompt
|
||||
value:
|
||||
expr: "`Subagent fanout synthesis check: delegate exactly two bounded subagents sequentially using sessions_spawn, not ACP.\nFirst spawn exactly one child with label ${alphaLabel} and task: verify that \\`HEARTBEAT.md\\` exists and reply exactly \\`ok\\` if it does. Wait for that child to finish.\nThen spawn exactly one child with label ${betaLabel} and task: verify that \\`repo/qa/scenarios/agents/subagent-fanout-synthesis.yaml\\` exists and reply exactly \\`ok\\` if it does. Wait for that child to finish.\nDo not spawn any more children after ${betaLabel} finishes.\nThen reply with exactly these two lines and nothing else:\nsubagent-1: ok\nsubagent-2: ok`"
|
||||
expr: "`Subagent fanout synthesis check: delegate exactly two bounded subagents sequentially using sessions_spawn, not ACP.\nFirst spawn exactly one child with label ${alphaLabel} and task: verify that \\`AGENTS.md\\` exists and reply exactly \\`ok\\` if it does. Wait for that child to finish.\nThen spawn exactly one child with label ${betaLabel} and task: verify that \\`repo/qa/scenarios/agents/subagent-fanout-synthesis.yaml\\` exists and reply exactly \\`ok\\` if it does. Wait for that child to finish.\nDo not spawn any more children after ${betaLabel} finishes.\nThen reply with exactly these two lines and nothing else:\nsubagent-1: ok\nsubagent-2: ok`"
|
||||
- set: sessionKey
|
||||
value:
|
||||
expr: "`agent:qa:fanout:${attempt}:${randomUUID().slice(0, 8)}`"
|
||||
|
||||
@@ -17,7 +17,6 @@ import {
|
||||
import {
|
||||
DEFAULT_AGENTS_FILENAME,
|
||||
DEFAULT_BOOTSTRAP_FILENAME,
|
||||
DEFAULT_HEARTBEAT_FILENAME,
|
||||
DEFAULT_IDENTITY_FILENAME,
|
||||
DEFAULT_SOUL_FILENAME,
|
||||
DEFAULT_TOOLS_FILENAME,
|
||||
@@ -43,7 +42,6 @@ export async function ensureSandboxWorkspace(
|
||||
DEFAULT_IDENTITY_FILENAME,
|
||||
DEFAULT_USER_FILENAME,
|
||||
DEFAULT_BOOTSTRAP_FILENAME,
|
||||
DEFAULT_HEARTBEAT_FILENAME,
|
||||
];
|
||||
for (const name of files) {
|
||||
const src = path.join(seed, name);
|
||||
|
||||
@@ -84,7 +84,7 @@ async function readWorkspaceFileWithGuards(params: {
|
||||
try {
|
||||
// A transient FS race (EAGAIN/EWOULDBLOCK/EINTR under load) on the open or
|
||||
// read must not drop the agent's bootstrap file for the turn — this reader
|
||||
// runs every turn for AGENTS/SOUL/HEARTBEAT/etc. Retry the whole open+read so
|
||||
// runs every turn for AGENTS/SOUL/TOOLS/etc. Retry the whole open+read so
|
||||
// each attempt uses a fresh fd (retrying readFileSync on the same fd could
|
||||
// return truncated content after a partial read); the inode-identity guard
|
||||
// in openRootFile still protects against a swapped file between attempts.
|
||||
|
||||
@@ -513,7 +513,7 @@ describe("Dockerfile", () => {
|
||||
expect(workflow).toContain("Smoke test arm64 runtime workspace templates");
|
||||
expect(workflow).toContain("test -f /app/src/agents/templates/HEARTBEAT.md");
|
||||
expect(workflow).toContain('grep -F "Missing workspace template:"');
|
||||
expect(workflow).toContain('test -f "${temp_root}/home/.openclaw/workspace/HEARTBEAT.md"');
|
||||
expect(workflow).not.toContain('test -f "${temp_root}/home/.openclaw/workspace/HEARTBEAT.md"');
|
||||
});
|
||||
|
||||
it("keeps only the runtime-assets prune proof in full release validation", async () => {
|
||||
|
||||
@@ -2935,6 +2935,27 @@ describe("agents.files.list", () => {
|
||||
expect(names).toContain("BOOTSTRAP.md");
|
||||
});
|
||||
|
||||
it("does not expose retired HEARTBEAT.md workspace files", async () => {
|
||||
const names = await listAgentFileNames();
|
||||
expect(names).not.toContain("HEARTBEAT.md");
|
||||
});
|
||||
|
||||
it("rejects writes to retired HEARTBEAT.md workspace files", async () => {
|
||||
const { respond, promise } = makeCall("agents.files.set", {
|
||||
agentId: "main",
|
||||
name: "HEARTBEAT.md",
|
||||
content: "legacy checklist",
|
||||
});
|
||||
await promise;
|
||||
|
||||
expectRecordFields(expectRespondErrorContaining(respond, "unsupported file"), {
|
||||
code: "INVALID_REQUEST",
|
||||
message: 'unsupported file "HEARTBEAT.md"',
|
||||
});
|
||||
expect(mocks.fsMkdir).not.toHaveBeenCalled();
|
||||
expect(mocks.rootWrite).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("hides BOOTSTRAP.md when workspace setup is complete", async () => {
|
||||
mockWorkspaceStateRead({ setupCompletedAt: "2026-02-15T14:00:00.000Z" });
|
||||
|
||||
|
||||
@@ -58,7 +58,6 @@ import {
|
||||
import {
|
||||
DEFAULT_AGENTS_FILENAME,
|
||||
DEFAULT_BOOTSTRAP_FILENAME,
|
||||
DEFAULT_HEARTBEAT_FILENAME,
|
||||
DEFAULT_IDENTITY_FILENAME,
|
||||
DEFAULT_MEMORY_FILENAME,
|
||||
DEFAULT_SOUL_FILENAME,
|
||||
@@ -110,7 +109,6 @@ const BOOTSTRAP_FILE_NAMES = [
|
||||
DEFAULT_TOOLS_FILENAME,
|
||||
DEFAULT_IDENTITY_FILENAME,
|
||||
DEFAULT_USER_FILENAME,
|
||||
DEFAULT_HEARTBEAT_FILENAME,
|
||||
DEFAULT_BOOTSTRAP_FILENAME,
|
||||
] as const;
|
||||
const BOOTSTRAP_FILE_NAMES_POST_ONBOARDING = BOOTSTRAP_FILE_NAMES.filter(
|
||||
|
||||
@@ -50,4 +50,4 @@ workspace root.
|
||||
|
||||
All paths are resolved from the workspace and must stay inside it (including realpath checks).
|
||||
Only recognized bootstrap basenames are loaded (`AGENTS.md`, `SOUL.md`, `TOOLS.md`,
|
||||
`IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`, `MEMORY.md`).
|
||||
`IDENTITY.md`, `USER.md`, `BOOTSTRAP.md`, `MEMORY.md`).
|
||||
|
||||
@@ -480,8 +480,8 @@ describe("renderAgentFiles", () => {
|
||||
missing: false,
|
||||
},
|
||||
{
|
||||
name: "HEARTBEAT.md",
|
||||
path: "/tmp/workspace/HEARTBEAT.md",
|
||||
name: "SOUL.md",
|
||||
path: "/tmp/workspace/SOUL.md",
|
||||
missing: false,
|
||||
},
|
||||
],
|
||||
@@ -501,9 +501,9 @@ describe("renderAgentFiles", () => {
|
||||
container,
|
||||
);
|
||||
|
||||
const heartbeatTab = expectAgentTab(container, "HEARTBEAT");
|
||||
expect(heartbeatTab.disabled).toBe(true);
|
||||
heartbeatTab.click();
|
||||
const soulTab = expectAgentTab(container, "SOUL");
|
||||
expect(soulTab.disabled).toBe(true);
|
||||
soulTab.click();
|
||||
expect(onSelectFile).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user