mercury-agent 0.16.1 → 0.16.3

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.
Files changed (83) hide show
  1. package/README.md +6 -0
  2. package/docs/README.md +50 -0
  3. package/docs/authoring-profiles.md +8 -0
  4. package/docs/behavior-layers.md +204 -0
  5. package/docs/extensions.md +2 -0
  6. package/docs/goals/football-reporter-profile/decisions.md +479 -0
  7. package/docs/goals/football-reporter-profile/goal.md +91 -0
  8. package/docs/goals/football-reporter-profile/roadmap.md +196 -0
  9. package/docs/goals/whatsapp-bot-hardening/README.md +43 -0
  10. package/docs/goals/whatsapp-bot-hardening/archive/ambient-group-context.md +211 -0
  11. package/docs/goals/whatsapp-bot-hardening/archive/command-routing-consistency.md +210 -0
  12. package/docs/goals/whatsapp-bot-hardening/archive/destructive-command-guards.md +218 -0
  13. package/docs/goals/whatsapp-bot-hardening/archive/docs-extension.md +182 -0
  14. package/docs/goals/whatsapp-bot-hardening/archive/handoff-2026-08-09.md +588 -0
  15. package/docs/goals/whatsapp-bot-hardening/archive/media-size-and-silent-drop.md +178 -0
  16. package/docs/goals/whatsapp-bot-hardening/archive/member-memory.md +199 -0
  17. package/docs/goals/whatsapp-bot-hardening/archive/message-author-attribution.md +211 -0
  18. package/docs/goals/whatsapp-bot-hardening/archive/run-from-source-switchover.md +212 -0
  19. package/docs/goals/whatsapp-bot-hardening/archive/setup-plan-2026-08-06.md +1117 -0
  20. package/docs/goals/whatsapp-bot-hardening/decisions.md +200 -0
  21. package/docs/goals/whatsapp-bot-hardening/goal.md +75 -0
  22. package/docs/goals/whatsapp-bot-hardening/open-threads.md +396 -0
  23. package/docs/goals/whatsapp-bot-hardening/roadmap.md +245 -0
  24. package/docs/memory.md +30 -0
  25. package/docs/profile-guide.md +483 -0
  26. package/docs/refactor/.gitkeep +0 -0
  27. package/docs/refactor/archive/.gitkeep +0 -0
  28. package/docs/refactor/audits/.gitkeep +0 -0
  29. package/docs/refactor/backlog/.gitkeep +0 -0
  30. package/docs/skills-guide.md +154 -0
  31. package/examples/extensions/README.md +1 -0
  32. package/examples/extensions/feed-watch/config.ts +354 -0
  33. package/examples/extensions/feed-watch/digest.ts +344 -0
  34. package/examples/extensions/feed-watch/feeds.ts +341 -0
  35. package/examples/extensions/feed-watch/index.ts +302 -0
  36. package/examples/extensions/feed-watch/items.ts +171 -0
  37. package/examples/extensions/feed-watch/match.ts +107 -0
  38. package/examples/extensions/feed-watch/prompts/verify.md +35 -0
  39. package/examples/extensions/feed-watch/skill/SKILL.md +128 -0
  40. package/examples/extensions/feed-watch/watch.ts +548 -0
  41. package/examples/extensions/longview/hook.ts +179 -16
  42. package/examples/extensions/longview/index.ts +13 -2
  43. package/examples/extensions/longview/prompts/summarize.md +3 -2
  44. package/examples/extensions/longview/render/telegraph-nodes.ts +21 -1
  45. package/examples/extensions/longview/summarize.ts +57 -14
  46. package/examples/extensions/napkin/index.ts +334 -86
  47. package/examples/extensions/napkin/pi-spawn.ts +196 -0
  48. package/examples/extensions/pinchtab/index.ts +37 -4
  49. package/examples/extensions/pinchtab/lib/session-injector.ts +31 -9
  50. package/examples/extensions/pinchtab/skill/SKILL.md +29 -0
  51. package/examples/profiles/_template/AGENTS.md +138 -0
  52. package/examples/profiles/_template/README.md +65 -0
  53. package/examples/profiles/_template/config.yaml +57 -0
  54. package/examples/profiles/_template/tasks/daily.md +32 -0
  55. package/examples/profiles/football-reporter/AGENTS.md +219 -0
  56. package/examples/profiles/football-reporter/README.md +138 -0
  57. package/examples/profiles/football-reporter/config.yaml +184 -0
  58. package/examples/profiles/football-reporter/seed/MEMORY.md +42 -0
  59. package/examples/profiles/football-reporter/seed/episodes/barcelona-2026-27.md +25 -0
  60. package/examples/profiles/football-reporter/seed/episodes/beitar-jerusalem-2026-27.md +25 -0
  61. package/examples/profiles/football-reporter/seed/episodes/maccabi-haifa-2026-27.md +24 -0
  62. package/examples/profiles/football-reporter/seed/episodes/man-united-2026-27.md +26 -0
  63. package/examples/profiles/football-reporter/seed/episodes/real-madrid-2026-27.md +25 -0
  64. package/examples/profiles/football-reporter/seed/napkin-distill.md +55 -0
  65. package/examples/profiles/football-reporter/tasks/daily-article.md +142 -0
  66. package/package.json +8 -5
  67. package/src/adapters/whatsapp.ts +20 -1
  68. package/src/agent/container-entry.ts +43 -6
  69. package/src/agent/container-runner.ts +32 -2
  70. package/src/cli/build-image-tags.ts +34 -0
  71. package/src/cli/mercury.ts +50 -4
  72. package/src/cli/mrctl.ts +9 -1
  73. package/src/config.ts +5 -3
  74. package/src/core/handler.ts +13 -1
  75. package/src/core/routes/config-builtin.ts +7 -0
  76. package/src/core/routes/dashboard.ts +117 -5
  77. package/src/core/routes/tasks.ts +28 -0
  78. package/src/core/runtime.ts +94 -13
  79. package/src/core/task-scheduler.ts +103 -12
  80. package/src/extensions/catalog.ts +9 -0
  81. package/src/profile/space-profile.ts +780 -0
  82. package/src/storage/db.ts +215 -0
  83. package/src/types.ts +56 -0
package/README.md CHANGED
@@ -217,6 +217,9 @@ mercury setup --profile https://github.com/user/mercury-stock-agent
217
217
  # Create from local directory
218
218
  mercury setup --profile ./my-profiles/ml-assistant
219
219
 
220
+ # Apply a profile non-interactively (deploy scripts, existing projects)
221
+ mercury profiles apply ./my-profiles/ml-assistant
222
+
220
223
  # List available profiles
221
224
  mercury profiles list
222
225
 
@@ -224,6 +227,8 @@ mercury profiles list
224
227
  mercury profiles export ./my-profile
225
228
  ```
226
229
 
230
+ Building one for a specific use-case — what goes in `AGENTS.md`, how to keep it accurate, memory, skills, tasks, permissions, testing — is covered in [docs/profile-guide.md](docs/profile-guide.md). A single space inside a general bot gets a **space profile** instead (`scripts/space-profile.ts`, scaffold in [`examples/profiles/_template/`](examples/profiles/_template/)).
231
+
227
232
  ---
228
233
 
229
234
  ## CLI
@@ -513,6 +518,7 @@ mrctl config set trigger_patterns "@Bot,Bot"
513
518
  - [Authentication](docs/auth/overview.md)
514
519
  - [Message pipeline](docs/pipeline.md)
515
520
  - [Memory system](docs/memory.md)
521
+ - **Building a bot for a use-case:** [Profile guide](docs/profile-guide.md) · [Behaviour layers](docs/behavior-layers.md) · [Skills guide](docs/skills-guide.md) · [Applicative profile contract](docs/authoring-profiles.md)
516
522
  - [Scheduled tasks](docs/scheduler.md)
517
523
  - [Permissions](docs/permissions.md)
518
524
  - [Media handling](docs/media/overview.md)
package/docs/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # Mercury — docs
2
+
3
+ Product docs, planning docs, ops runbooks and workflow scaffolding for
4
+ [mercury](https://github.com/Avishai-Tsabari/mercury). All of it lives in this
5
+ repository, tracked normally.
6
+
7
+ ## Layout
8
+
9
+ ```
10
+ docs/
11
+ configuration.md, pipeline.md, auth/, security/, ... product & reference docs
12
+ runbooks/ operational runbooks (release steps, OAuth setup)
13
+ goals/{slug}/ multi-milestone goals (goal, roadmap, decisions)
14
+ ideas/{slug}.md raw ideas, not yet planned
15
+ backlog/{slug}.md goal + architecture approved, not started
16
+ in-progress/{slug}.md active implementation
17
+ archive/{slug}.md shipped or abandoned
18
+ bugs/{slug}.md open bug reports
19
+ debug/{severity}/ bug post-mortems
20
+ refactor/ audits, active refactor docs, archive
21
+ notes/, templates/, html-slides/, pending-updates/
22
+ ROADMAP.md single source of truth for priority
23
+ ```
24
+
25
+ ## Content rule
26
+
27
+ The repo is private, but "private" is not "unreviewed". For everything under
28
+ `docs/`:
29
+
30
+ - **Name secrets, never paste values.** `MERCURY_ANTHROPIC_API_KEY`, not the key.
31
+ - **Keep third-party identifiers out unless they carry the finding.** A phone
32
+ number, WhatsApp JID or LID belongs in a doc only when the identifier *is* the
33
+ evidence — a post-mortem about LID resolution may quote one; a setup guide may
34
+ not.
35
+
36
+ ## History
37
+
38
+ Until 2026-08-19 the scaffolding lived in a second private repository,
39
+ `saharw01/mercury-planning`, whose working tree *was* this directory — a
40
+ workaround from when mercury was public and planning docs were kept out of it by
41
+ policy (PR #22, 2026-08-10).
42
+
43
+ That is over. The repo is private, PRs #46/#47 brought `docs/debug/` and
44
+ `docs/runbooks/` back under version control, and the rest of the scaffolding
45
+ followed. The planning repo's 44 commits were merged in with `-X subtree=docs`,
46
+ so authorship and per-file history survive; `git log --follow` traces through
47
+ both the original subtree split (mercury `d5d2aa6`) and the re-merge.
48
+
49
+ There is one repo and one `git status` again. Nothing here needs a second remote,
50
+ a nested `.git`, or an allowlist in `.git/info/exclude`.
@@ -1,5 +1,13 @@
1
1
  # Authoring Applicative Profiles
2
2
 
3
+ > This page is the **contract** — manifest, broker, permissions. For *how to
4
+ > design* a profile that is accurate and stays in character (the layer map,
5
+ > facts inventory, `AGENTS.md` shape, memory, skills, tasks, testing) read
6
+ > [`profile-guide.md`](profile-guide.md) first; for what the model actually
7
+ > receives, [`behavior-layers.md`](behavior-layers.md). Per-space profiles
8
+ > (one space inside a general bot) use `scripts/space-profile.ts` instead of
9
+ > this manifest — see `examples/profiles/_template/`.
10
+
3
11
  The contract for building a **profile** — a package of deterministic business
4
12
  logic that wraps raw capabilities (Calendar, email, …) and scopes what members
5
13
  can do. Mercury (this repo) provides the schema, loader, permission scoping, and
@@ -0,0 +1,204 @@
1
+ # Behaviour layers — where a rule lives, and what the model actually receives
2
+
3
+ Every agent run is assembled from several layers written by different people
4
+ at different times: the platform prompt baked into the image, an optional
5
+ applicative profile, the owner's global character, the global `AGENTS.md`, the
6
+ space `AGENTS.md`, space preferences, space config, task prompts, and the
7
+ memory files in the workspace. Most "the bot ignores my instruction" reports
8
+ are two of these layers disagreeing. This page is the verified map — what is
9
+ sent, in what order, who owns it, and when a change takes effect.
10
+
11
+ Verified against `src/agent/container-entry.ts`, `src/core/runtime.ts`,
12
+ `src/storage/db.ts` and pi 0.84.2's `resource-loader.js` / `system-prompt.js`
13
+ (inside the agent image) on 2026-08-21. Re-verify by grepping the image, not
14
+ the repo, after a pi upgrade.
15
+
16
+ ## 1. The system prompt, top to bottom
17
+
18
+ ```
19
+ 1. pi preamble ............................ image container-entry.ts buildSystemPrompt
20
+ "You are an expert AI assistant…", tool list, "Be concise"
21
+ (override mode; OVERRIDE_PI_SYSTEM_PROMPT)
22
+ 2. Mercury platform block .................. image container-entry.ts buildMercuryAdditions
23
+ inbox/outbox · "You are <bot_username>; read /docs/mercury"
24
+ ## Permissions & Security ("Permission denied → simply inform the user")
25
+ ## Moderation ("warn first, then mute" — only for a caller holding mutes.mute)
26
+ ## Environment Variables
27
+ ## Current model capabilities
28
+ ## Memory (MEMORY.md, <active_episodes>, <members>, member notes)
29
+ ## Run budget (tools-capable models only)
30
+ ## Destructive Operations — Confirmation Required
31
+ ## Presenting tool results ("simple lists", "never show JSON/commands")
32
+ ## Character (mrctl character flow + "standing instruction → set a preference"
33
+ — only for a caller holding prefs.set)
34
+ reply-anchor sentence (swipe-replies only)
35
+ 3. MERCURY_EXT_SYSTEM_PROMPT ............... host runtime.ts ~1700-1760
36
+ a. extension before_container `systemPrompt` fragments
37
+ b. applicative profile `profile_prompt` (.mercury/active-profile.json)
38
+ c. "## Bot Character (set by the owner — applies to all conversations)"
39
+ (project_config.character;
40
+ skipped when persona.exclusive=true)
41
+ d. space `system_prompt` (space_config, dashboard-set)
42
+ 4. <project_context> ....................... pi resource-loader.js loadProjectContextFiles
43
+ <project_instructions path="/home/mercury/.pi/agent/AGENTS.md"> ← .mercury/global/AGENTS.md
44
+ (not mounted when persona.exclusive=true)
45
+ <project_instructions path="/spaces/<space>/AGENTS.md"> ← the space AGENTS.md
46
+ (pi walks from cwd to /; only the space dir is mounted, so only that
47
+ file and the global one exist. AGENTS.override.md / CLAUDE.md are
48
+ accepted names too; AGENTS.md is the convention.)
49
+ 5. <available_skills> ...................... pi skills.js formatSkillsForPrompt
50
+ name + description + SKILL.md path for every skill under
51
+ /home/mercury/.pi/agent/skills/** ← .mercury/global/skills/ (extension + built-in skills)
52
+ /spaces/<space>/.pi/skills/** ← space-local skills
53
+ 6. "Current working directory: /spaces/<space>"
54
+ ```
55
+
56
+ Two consequences worth reading twice:
57
+
58
+ - **Layers 1–3 are prose the model treats as equally authoritative.** Nothing
59
+ ranks "space AGENTS.md" above "## Moderation". When two of them speak to the
60
+ same subject the outcome is a coin flip weighted towards whichever is more
61
+ specific and later — and the platform text itself says so: *"a per-space
62
+ rule that is meant to override a global one has to say so in words rather
63
+ than rely on being more specific."* The only reliable override is an
64
+ explicit sentence naming what it overrides, plus deleting the competing
65
+ rule wherever you control it.
66
+ - **Layer 2 is mostly unconditional, and two voices are removable.** Every
67
+ space receives the security text, the destructive-ops rule and the "simple
68
+ lists, never raw output" paragraph. Two paragraphs are *capability* text
69
+ and are emitted only when the caller can act on them: "## Moderation" for a
70
+ caller holding `mutes.mute`, "## Character" (the preference / character
71
+ flow) for a caller holding `prefs.set` — a member without `prefs.set` is no
72
+ longer told that "a standing instruction → set a preference". And a space
73
+ that owns its standard can set `persona.exclusive=true` (`space_config`,
74
+ profile-owned): the host then leaves the owner's Bot Character (3c) out of
75
+ its prompt and does not mount the global `AGENTS.md` (4), so the space file
76
+ is the only persona left. Everything that still reaches such a space (the
77
+ platform text, skills, a per-space `system_prompt`) is unchanged. A persona
78
+ that contradicts what remains (a reporter who must not offer lists) still
79
+ has to say so in its `AGENTS.md`, in words.
80
+
81
+ ## 2. The user prompt, top to bottom
82
+
83
+ Built by `buildPrompt()` in `container-entry.ts`:
84
+
85
+ ```
86
+ <caller id name role space/>
87
+ <run_budget>…</run_budget> wall clock for this run
88
+ <episodic_memory>…</episodic_memory> /spaces/<space>/MEMORY.md, verbatim, if present
89
+ <active_episodes>…</active_episodes> knowledge/episodes/*.md, keyword-scored (see §5)
90
+ <history>…</history> sliding window of stored turns (see §4)
91
+ <ambient_messages>…</ambient_messages> overheard group messages (ambient.enabled)
92
+ <members>…</members> space_roles — authoritative id→name→role
93
+ <member_notes>…</member_notes> knowledge/members/<id>.md, ≤6000 chars
94
+ <preferences>…</preferences> space_preferences rows
95
+ <attachments>…</attachments>
96
+ <reply_anchor>…</reply_anchor> swipe-replies only
97
+ <the prompt> chat message, or the task prompt, plus any
98
+ before_container promptAppend (e.g. a digest)
99
+ ```
100
+
101
+ A scheduled task uses exactly the same assembly; its prompt row is "the
102
+ prompt", and it runs as the caller who created it.
103
+
104
+ ## 3. Ownership, surface, and when a change lands
105
+
106
+ | Layer | Owner | Set from | Takes effect |
107
+ |---|---|---|---|
108
+ | pi preamble, Mercury platform block | mercury (code) | `src/agent/container-entry.ts` | **agent image rebuild** (`container/build.sh`), not a restart |
109
+ | `profile_prompt`, `member_permissions` | deploy (applicative profile) | `mercury profiles apply <dir>` → `.mercury/active-profile.json` | **restart** (read at startup) |
110
+ | Bot Character | bot owner (global admin) | `mrctl character set --file`, `PUT /api/character`, dashboard | next run; left out of a `persona.exclusive` space |
111
+ | space `system_prompt` | space admin | dashboard Spaces settings (`space_config.system_prompt`) | next run |
112
+ | global `AGENTS.md` | deploy | `.mercury/global/AGENTS.md` (written by `mercury init` from `resources/templates/AGENTS.md`, overwritten by an applicative profile's `agents_md`) | next run (mounted `:ro`); not mounted for a `persona.exclusive` space |
113
+ | space `AGENTS.md` | space profile / operator | `.mercury/spaces/<space>/AGENTS.md`; `scripts/space-profile.ts apply` | next run (mounted per run) |
114
+ | space preferences | space admin (`prefs.set`) | `mrctl prefs set/delete`; ≤500 chars each, ≤50 per space | next run |
115
+ | space config (`trigger.*`, `context.*`, `ambient.enabled`, `persona.exclusive`, `role.<r>.permissions`, `<ext>.<key>`, `model.active`, `system_prompt`) | space admin / dashboard / profile | `mrctl config set`, dashboard, `space-profile apply` (`extension_config`) | next run (per-run read) |
116
+ | task prompts | whoever owns the `tasks` row | `mrctl tasks create`, dashboard, `space-profile apply` (`tasks:`) | next scheduled run |
117
+ | `MEMORY.md`, `knowledge/**` | the agent (and napkin's jobs) | `write` tool in-container; host edits | next run |
118
+ | extension skills | extension | `mercury.skill("./skill")` → copied to `.mercury/global/skills/<name>/` at startup | **restart** |
119
+ | space-local skills | operator / profile | `.mercury/spaces/<space>/.pi/skills/<name>/SKILL.md` | next run |
120
+ | `mercury.yaml` (`model.chain`, `context.window_size` default, `agent.trace_runs`, `extensions:` defaults) | operator | file + restart; `MERCURY_*` env wins over YAML | restart (some keys, e.g. `model.active`, are per-run) |
121
+
122
+ "Next run" means the running bot does not need a restart. Two traps:
123
+
124
+ - A restart never redeploys anything in layer 1 — `container-entry.ts` is
125
+ baked into the image. Verify by grepping the image
126
+ (`docker run --rm --entrypoint grep <image> -c "<marker>" /path`), never
127
+ the repo.
128
+ - `MERCURY_*` env overrides `mercury.yaml`; a YAML edit can silently do
129
+ nothing.
130
+
131
+ ## 4. The history window
132
+
133
+ - `context.mode` is a per-space key. `main` and DM auto-spaces are seeded
134
+ `context`; **any other space defaults to `clear`** (no history at all — only
135
+ the reply chain when someone swipe-replies). Set it explicitly.
136
+ - `context.window_size` (default 10 — `config.ts contextWindowSize`) counts
137
+ **user turns**: `getRecentTurns` takes the newest `turnCount*5` non-ambient
138
+ rows after the compact boundary and cuts at the Nth user row. Assistant rows
139
+ ride along. Scheduled runs are user rows too, so a space with six
140
+ scheduled runs a day spends most of its window on procedure text.
141
+ - A swipe-reply halves the window (`floor(window/2)`) and prepends the
142
+ replied-to chain (`context.reply_chain_depth`).
143
+ - `mrctl compact` moves the boundary permanently; `mrctl clear` clears the
144
+ next run only; `mrctl recall "<words>"` is a substring search over the
145
+ whole stored history for anything outside the window.
146
+ - Ambient messages have their own budget (30 rows) and do not compete with
147
+ turns.
148
+
149
+ The window is a *recent-conversation* mechanism, not a memory. Anything the
150
+ bot must get right a week later belongs in a file (§5), not in the hope that
151
+ it is still inside the window.
152
+
153
+ ## 5. Memory surfaces (what is injected, when)
154
+
155
+ | Surface | File | Injected | Condition |
156
+ |---|---|---|---|
157
+ | Episodic memory | `MEMORY.md` in the space dir | every run, verbatim, as `<episodic_memory>` | file exists and is non-empty. No size cap is enforced — the prompt asks for ~1500 tokens |
158
+ | Active episodes | `knowledge/episodes/*.md` | per run, as `<active_episodes>`, ≤800 tokens | frontmatter `status: active|cooling`, `keywords: ["…"]` (JSON array); score = keyword overlap × (active 1.0 / cooling 0.5) × log(mentions+1); body = `summary:` + `## Current State` |
159
+ | Member notes | `knowledge/members/<id>.md` | per run, as `<member_notes>` | `<id>` = platform id with `/`→`_`; ≤6000 chars total |
160
+ | Members | `space_roles` table | per run, as `<members>` | always; authoritative identity |
161
+ | Preferences | `space_preferences` | per run, as `<preferences>` | always |
162
+ | Vault entities | `knowledge/{people,projects,references,daily}/` | **not injected** | the agent must `read`/`napkin search` them; napkin's distillation job writes them |
163
+ | Anything else in the workspace | `knowledge/*.md`, `outbox/`, … | **not injected** | the agent reads it only if a rule tells it to (e.g. the football profile's `knowledge/push-log.md`) |
164
+
165
+ So: the only *always-on* memories are `MEMORY.md`, preferences and member
166
+ notes. Episodes need keywords that will actually appear in future messages.
167
+ Everything else is opt-in by instruction.
168
+
169
+ ## 6. Which layer for which kind of rule
170
+
171
+ | Kind of rule | Put it in | Not in |
172
+ |---|---|---|
173
+ | Who the bot is in this space, register, what it covers, sourcing and accuracy standard, formats, when it stays silent | space `AGENTS.md` | preferences (500-char blocks in the user prompt, no structure, easy to contradict) |
174
+ | A procedure: when it runs, what it produces, where it goes | the task prompt (`tasks/*.md` in a space profile) | `AGENTS.md` (a task prompt never repeats an editorial rule; `AGENTS.md` never describes a schedule) |
175
+ | A one-line behavioural setting a space admin may change from chat (`language`, `timezone`) | preference | `AGENTS.md` (would need a deploy to change) |
176
+ | Voice that must hold across all spaces of one deployment | Bot Character | every space's `AGENTS.md` (drifts) |
177
+ | Deterministic business logic, credentials, anything with numbers or dates | a capability / engine / extension, returning structured facts | prompt prose ("compute the day name yourself") |
178
+ | What members may do | `role.member.permissions` / applicative `member_permissions` | prompt prose ("only admins may…") — the model is not the enforcement |
179
+ | Knobs an extension reads (`feed-watch.*`, `longview.*`) | `extension_config` in the space profile (repo-owned, drift-checked) | hand edits on the box |
180
+ | A fact the bot keeps getting wrong | a file the bot reads each turn (`MEMORY.md`, a notebook under `knowledge/`), written with source and date | a longer rule |
181
+
182
+ One rule in exactly one layer. A rule repeated "for emphasis" is the next
183
+ contradiction — and when you move a rule into `AGENTS.md`, delete the
184
+ preference it came from (`remove_preferences:` in a space profile exists for
185
+ this).
186
+
187
+ ## 7. Reading the live layers
188
+
189
+ ```bash
190
+ # Everything the football space receives, without touching it
191
+ bun scripts/space-profile.ts dump --project ~/whatsapp-bot --space football-friends
192
+
193
+ # Drift between the repo profile and the live space
194
+ bun scripts/space-profile.ts check --project ~/whatsapp-bot --profile examples/profiles/football-reporter
195
+
196
+ # The exact prompt a run received (requires agent.trace_runs: true + image rebuild)
197
+ ls .mercury/traces/ # <container-name>.jsonl, 7-day TTL
198
+ ```
199
+
200
+ `agent.trace_runs` is off by default and needs the image rebuilt when
201
+ toggled. With it off, "what did the model actually see and open?" is
202
+ unanswerable after the fact — turn it on for a bounded window whenever you
203
+ are tuning a profile. A trace holds the full prompt and reply in clear text;
204
+ treat it like debug logging.
@@ -121,6 +121,8 @@ The directory must contain a `SKILL.md` file in pi's [skill format](https://agen
121
121
 
122
122
  Skills can contain multiple files — scripts, references, assets — not just SKILL.md. The agent uses relative paths from SKILL.md to access them.
123
123
 
124
+ Only the `name`, `description` and path of each skill reach the system prompt; the agent reads the body on demand when the description matches. How to write a description that fires, where space-local skills must live (`.mercury/spaces/<space>/.pi/skills/`), and how to make a profile actually use its skills: [skills-guide.md](skills-guide.md).
125
+
124
126
  ### `mercury.requires(capabilities)`
125
127
 
126
128
  Declare that this extension's skill (or CLI workflows) needs certain model capabilities (`tools`, `vision`, etc.). If **no** leg in `MERCURY_MODEL_CHAIN` satisfies **all** listed flags, the extension skill is not copied into the global skills directory and Mercury logs a startup warning.