mercury-agent 0.5.0 → 0.5.2

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 (125) hide show
  1. package/README.md +452 -451
  2. package/container/Dockerfile +127 -127
  3. package/container/Dockerfile.base +109 -109
  4. package/container/Dockerfile.power +17 -17
  5. package/container/agent-package.json +8 -8
  6. package/container/build.sh +54 -54
  7. package/docs/ROADMAP.md +3 -4
  8. package/docs/archive/summarization/2026-07-02-recent-dev-summary.md +71 -0
  9. package/docs/auth/dashboard.md +28 -28
  10. package/docs/auth/overview.md +109 -109
  11. package/docs/auth/whatsapp.md +173 -173
  12. package/docs/authoring-profiles.md +174 -174
  13. package/docs/configuration.md +54 -54
  14. package/docs/container-lifecycle.md +349 -349
  15. package/docs/{bugs/bwrap-privileged-linux-docker.md → debug/major/2026-07-02-bwrap-privileged-linux-docker.md} +21 -1
  16. package/docs/{bugs/e2big-prompt-delivery-fix.md → debug/major/2026-07-02-e2big-prompt-delivery-fix.md} +27 -1
  17. package/docs/{bugs/registry-pull-no-local-fallback.md → debug/major/2026-07-02-registry-pull-no-local-fallback.md} +27 -1
  18. package/docs/debug/summarization/2026-07-02-common-bug-patterns.md +72 -0
  19. package/docs/deployment.md +199 -199
  20. package/docs/extensions.md +375 -375
  21. package/docs/graceful-shutdown.md +62 -62
  22. package/docs/kb-distillation.md +77 -77
  23. package/docs/media/overview.md +140 -140
  24. package/docs/media/whatsapp.md +171 -171
  25. package/docs/memory.md +137 -137
  26. package/docs/permissions.md +217 -217
  27. package/docs/pipeline.md +228 -228
  28. package/docs/prd-chat-memory.md +76 -76
  29. package/docs/prd-config-load.md +82 -82
  30. package/docs/rate-limiting.md +229 -229
  31. package/docs/runbooks/publish-checklist.md +9 -1
  32. package/docs/scheduler.md +288 -288
  33. package/docs/setup-discord.md +100 -100
  34. package/docs/setup-slack.md +119 -119
  35. package/docs/setup-whatsapp.md +94 -94
  36. package/docs/subagents.md +166 -166
  37. package/docs/web-search.md +62 -62
  38. package/examples/extensions/README.md +12 -12
  39. package/examples/extensions/charts/index.ts +13 -13
  40. package/examples/extensions/charts/skill/SKILL.md +98 -98
  41. package/examples/extensions/gws/README.md +52 -52
  42. package/examples/extensions/gws/skill/SKILL.md +57 -57
  43. package/examples/extensions/gws/skill/references/calendar.md +101 -101
  44. package/examples/extensions/gws/skill/references/docs.md +65 -65
  45. package/examples/extensions/gws/skill/references/drive.md +79 -79
  46. package/examples/extensions/gws/skill/references/gmail.md +85 -85
  47. package/examples/extensions/gws/skill/references/sheets.md +60 -60
  48. package/examples/extensions/napkin/skill/SKILL.md +728 -728
  49. package/examples/extensions/pdf/skill/LICENSE.txt +30 -30
  50. package/examples/extensions/pdf/skill/SKILL.md +314 -314
  51. package/examples/extensions/pdf/skill/forms.md +294 -294
  52. package/examples/extensions/pdf/skill/reference.md +611 -611
  53. package/examples/extensions/pdf/skill/scripts/check_bounding_boxes.py +65 -65
  54. package/examples/extensions/pdf/skill/scripts/check_fillable_fields.py +11 -11
  55. package/examples/extensions/pdf/skill/scripts/convert_pdf_to_images.py +33 -33
  56. package/examples/extensions/pdf/skill/scripts/create_validation_image.py +37 -37
  57. package/examples/extensions/pdf/skill/scripts/extract_form_field_info.py +122 -122
  58. package/examples/extensions/pdf/skill/scripts/extract_form_structure.py +115 -115
  59. package/examples/extensions/pdf/skill/scripts/fill_fillable_fields.py +98 -98
  60. package/examples/extensions/pdf/skill/scripts/fill_pdf_form_with_annotations.py +107 -107
  61. package/examples/extensions/permission-guard/index.ts +65 -65
  62. package/examples/extensions/pinchtab/skill/SKILL.md +224 -224
  63. package/examples/extensions/pinchtab/skill/TRUST.md +69 -69
  64. package/examples/extensions/pinchtab/skill/references/api.md +297 -297
  65. package/examples/extensions/pinchtab/skill/references/env.md +45 -45
  66. package/examples/extensions/pinchtab/skill/references/profiles.md +107 -107
  67. package/examples/extensions/tradestation/host/refresh.ts +102 -102
  68. package/examples/extensions/tradestation/index.ts +153 -153
  69. package/examples/extensions/tradestation/skill/SKILL.md +67 -67
  70. package/examples/extensions/voice-synth/index.ts +94 -94
  71. package/examples/extensions/voice-synth/skill/SKILL.md +38 -38
  72. package/examples/extensions/voice-transcribe/requirements.txt +8 -8
  73. package/examples/extensions/voice-transcribe/scripts/transcribe.py +179 -179
  74. package/examples/extensions/voice-transcribe/skill/SKILL.md +53 -53
  75. package/examples/extensions/yahoo-mail/cli/package.json +13 -13
  76. package/examples/extensions/yahoo-mail/skill/SKILL.md +78 -78
  77. package/package.json +106 -106
  78. package/resources/agents/explore.md +50 -50
  79. package/resources/agents/worker.md +24 -24
  80. package/resources/connection-env-vars.json +25 -25
  81. package/resources/pi-extensions/subagent/agents.ts +126 -126
  82. package/resources/pi-extensions/subagent/index.ts +964 -964
  83. package/resources/profiles/coding/AGENTS.md +43 -43
  84. package/resources/profiles/coding/mercury-profile.yaml +15 -15
  85. package/resources/profiles/general/AGENTS.md +31 -31
  86. package/resources/profiles/general/mercury-profile.yaml +15 -15
  87. package/resources/profiles/research/AGENTS.md +40 -40
  88. package/resources/profiles/research/mercury-profile.yaml +15 -15
  89. package/resources/skills/config/SKILL.md +25 -25
  90. package/resources/skills/context/SKILL.md +33 -33
  91. package/resources/skills/conversation-recap/SKILL.md +19 -19
  92. package/resources/skills/mutes/SKILL.md +31 -31
  93. package/resources/skills/permissions/SKILL.md +19 -19
  94. package/resources/skills/preferences/SKILL.md +31 -31
  95. package/resources/skills/recall/SKILL.md +24 -24
  96. package/resources/skills/roles/SKILL.md +18 -18
  97. package/resources/skills/spaces/SKILL.md +18 -18
  98. package/resources/skills/tasks/SKILL.md +45 -45
  99. package/resources/templates/AGENTS.md +157 -157
  100. package/resources/templates/env.template +38 -38
  101. package/resources/templates/mercury.example.yaml +99 -99
  102. package/src/agent/container-entry.ts +1 -1
  103. package/src/agent/container-runner.ts +1345 -1346
  104. package/src/cli/mercury.ts +39 -7
  105. package/src/cli/mrctl.ts +636 -636
  106. package/src/config-file.ts +540 -540
  107. package/src/config.ts +339 -339
  108. package/src/core/api.ts +125 -125
  109. package/src/core/caller-token.ts +101 -101
  110. package/src/core/permissions.ts +228 -228
  111. package/src/core/profiles.ts +271 -271
  112. package/src/core/routes/capability.ts +70 -70
  113. package/src/core/routes/index.ts +15 -15
  114. package/src/core/runtime.ts +1530 -1530
  115. package/src/dashboard/index.html +729 -729
  116. package/src/extensions/api.ts +273 -273
  117. package/src/extensions/loader.ts +286 -286
  118. package/src/extensions/types.ts +517 -517
  119. package/src/main.ts +605 -605
  120. package/docs/pending-updates/applicative-profiles.md +0 -15
  121. package/docs/pending-updates/caller-bound-capability-token.md +0 -15
  122. package/docs/pending-updates/dm-auto-space.md +0 -15
  123. /package/docs/archive/{2026-07-01-applicative-profiles.md → applicative-profiles/2026-07-01-applicative-profiles.md} +0 -0
  124. /package/docs/archive/{2026-07-01-caller-bound-capability-token.md → applicative-profiles/2026-07-01-caller-bound-capability-token.md} +0 -0
  125. /package/docs/archive/{2026-07-01-dm-auto-space.md → applicative-profiles/2026-07-01-dm-auto-space.md} +0 -0
@@ -1,127 +1,127 @@
1
- # syntax=docker/dockerfile:1
2
- # Mercury Agent Container
3
- # Bun binary copied from official image — avoids bun.sh/install script deps
4
- FROM oven/bun:1 AS bun-source
5
- FROM node:22-slim AS node-source
6
- FROM golang:1.24.1 AS go-source
7
-
8
- FROM ubuntu:24.04
9
-
10
- ENV DEBIAN_FRONTEND=noninteractive
11
-
12
- # Install dev tools and language runtimes
13
- RUN apt-get update && apt-get install -y --no-install-recommends \
14
- # Core tools
15
- ca-certificates git curl wget jq vim zsh openssh-client gpg unzip \
16
- build-essential \
17
- # Python
18
- python3 python3-pip python3-venv \
19
- # Sandboxing: bubblewrap for defense-in-depth in runc mode.
20
- # Not used when CONTAINER_RUNTIME=runsc (gVisor handles isolation at the syscall boundary).
21
- # Remove once runc mode is deprecated.
22
- bubblewrap \
23
- && rm -rf /var/lib/apt/lists/*
24
-
25
- # Rename the built-in ubuntu user (UID 1000) to mercury
26
- # Ubuntu 24.04 ships with an 'ubuntu' user at UID/GID 1000; useradd -u 1000 fails with exit code 4
27
- RUN usermod -l mercury -d /home/mercury -m ubuntu && groupmod -n mercury ubuntu
28
-
29
- # Copy Bun from official image
30
- COPY --from=bun-source /usr/local/bin/bun /usr/local/bin/bun
31
- COPY --from=bun-source /usr/local/bin/bunx /usr/local/bin/bunx
32
-
33
- # Copy Node.js from official image (avoids flaky nodesource apt repository)
34
- # npm/npx are symlinks in the upstream image; Docker COPY dereferences single-file
35
- # symlinks, so recreate them with ln -s after copying node_modules.
36
- COPY --from=node-source /usr/local/bin/node /usr/local/bin/node
37
- COPY --from=node-source /usr/local/lib/node_modules /usr/local/lib/node_modules
38
- COPY --from=node-source /usr/local/include/node /usr/local/include/node
39
- RUN ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm && \
40
- ln -s /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx
41
- ENV HOME="/home/mercury"
42
- ENV BUN_INSTALL="/home/mercury/.bun"
43
- ENV PATH="$BUN_INSTALL/bin:/usr/local/bin:$PATH"
44
-
45
- # Copy Go from official image (avoids curl installer and network flakiness)
46
- COPY --from=go-source /usr/local/go /usr/local/go
47
- ENV PATH="/usr/local/go/bin:$PATH"
48
-
49
- # Install Playwright + Chromium (used by multiple extensions: web-browser, diagrams, charts)
50
- # HOME=/home/mercury causes playwright to install browsers to /home/mercury/.cache/ms-playwright
51
- RUN npx playwright install --with-deps chromium
52
-
53
- # Point puppeteer to Playwright's Chromium so npm packages skip downloading their own
54
- ENV PUPPETEER_SKIP_DOWNLOAD=true
55
- RUN ln -sf $(find /home/mercury/.cache/ms-playwright -name chrome -type f | head -1) /usr/local/bin/chromium
56
- ENV PUPPETEER_EXECUTABLE_PATH=/usr/local/bin/chromium
57
-
58
- # Allow Chromium to run without sandbox in Docker (required for non-root too)
59
- RUN echo '{"args":["--no-sandbox"]}' > /home/mercury/.puppeteerrc.json
60
- ENV CHROMIUM_FLAGS="--no-sandbox"
61
-
62
- # Install CLIs
63
- RUN bun add -g @mariozechner/pi-coding-agent@^0.67.2
64
-
65
- WORKDIR /app
66
-
67
- COPY container/agent-package.json /app/package.json
68
- RUN bun install --production
69
-
70
- # Patch pi: skip thinkingConfig for Gemma models (Google API rejects thinkingBudget for them,
71
- # but pi marks gemma-4 as reasoning:true and sends thinkingBudget:0 to disable it)
72
- RUN node <<'EOF'
73
- const fs = require('fs'), path = require('path');
74
- function patch(dir) {
75
- try {
76
- for (const f of fs.readdirSync(dir)) {
77
- const p = path.join(dir, f);
78
- try {
79
- if (fs.statSync(p).isDirectory()) patch(p);
80
- else if (f === 'google.js' && p.includes('@mariozechner/pi-ai')) {
81
- let c = fs.readFileSync(p, 'utf8');
82
- const noThinking = '&& !model.id.startsWith("gemma")';
83
- const p1 = 'if (options.thinking?.enabled && model.reasoning) {';
84
- const p2 = 'else if (model.reasoning && options.thinking && !options.thinking.enabled) {';
85
- if (!c.includes(noThinking)) {
86
- c = c.replace(p1, 'if (options.thinking?.enabled && model.reasoning ' + noThinking + ') {');
87
- c = c.replace(p2, 'else if (model.reasoning && options.thinking && !options.thinking.enabled ' + noThinking + ') {');
88
- fs.writeFileSync(p, c);
89
- console.log('Patched:', p);
90
- }
91
- }
92
- } catch(e) {}
93
- }
94
- } catch(e) {}
95
- }
96
- patch('/home/mercury/.bun');
97
- patch('/app/node_modules');
98
- EOF
99
-
100
- COPY src/agent/container-entry.ts /app/src/agent/container-entry.ts
101
- COPY src/agent/model-capabilities-core.ts /app/src/agent/model-capabilities-core.ts
102
- COPY src/agent/pi-failure-class.ts /app/src/agent/pi-failure-class.ts
103
- COPY src/agent/pi-jsonl-parser.ts /app/src/agent/pi-jsonl-parser.ts
104
- COPY src/agent/preferences-prompt.ts /app/src/agent/preferences-prompt.ts
105
- COPY src/cli/mrctl.ts /app/src/cli/mrctl.ts
106
- COPY src/cli/mrctl-http.ts /app/src/cli/mrctl-http.ts
107
- COPY src/extensions/reserved.ts /app/src/extensions/reserved.ts
108
- COPY src/extensions/permission-guard.ts /app/src/extensions/permission-guard.ts
109
- COPY src/types.ts /app/src/types.ts
110
- COPY resources/ /app/resources/
111
- COPY examples/extensions/ /tmp/examples-extensions/
112
- RUN while IFS= read -r ext || [ -n "$ext" ]; do \
113
- ext=$(echo "$ext" | xargs); \
114
- [ -z "$ext" ] && continue; \
115
- cp -r "/tmp/examples-extensions/$ext" "/app/resources/extensions/$ext"; \
116
- done < /app/resources/builtin-extensions.txt && \
117
- rm -rf /tmp/examples-extensions/
118
-
119
- RUN echo '#!/bin/sh\nbun run /app/src/cli/mrctl.ts "$@"' > /usr/local/bin/mrctl && \
120
- chmod +x /usr/local/bin/mrctl
121
-
122
- # Fix ownership of all mercury home dir artifacts before switching user
123
- RUN chown -R mercury:mercury /home/mercury
124
-
125
- USER mercury
126
-
127
- ENTRYPOINT ["bun", "run", "/app/src/agent/container-entry.ts"]
1
+ # syntax=docker/dockerfile:1
2
+ # Mercury Agent Container
3
+ # Bun binary copied from official image — avoids bun.sh/install script deps
4
+ FROM oven/bun:1 AS bun-source
5
+ FROM node:22-slim AS node-source
6
+ FROM golang:1.24.1 AS go-source
7
+
8
+ FROM ubuntu:24.04
9
+
10
+ ENV DEBIAN_FRONTEND=noninteractive
11
+
12
+ # Install dev tools and language runtimes
13
+ RUN apt-get update && apt-get install -y --no-install-recommends \
14
+ # Core tools
15
+ ca-certificates git curl wget jq vim zsh openssh-client gpg unzip \
16
+ build-essential \
17
+ # Python
18
+ python3 python3-pip python3-venv \
19
+ # Sandboxing: bubblewrap for defense-in-depth in runc mode.
20
+ # Not used when CONTAINER_RUNTIME=runsc (gVisor handles isolation at the syscall boundary).
21
+ # Remove once runc mode is deprecated.
22
+ bubblewrap \
23
+ && rm -rf /var/lib/apt/lists/*
24
+
25
+ # Rename the built-in ubuntu user (UID 1000) to mercury
26
+ # Ubuntu 24.04 ships with an 'ubuntu' user at UID/GID 1000; useradd -u 1000 fails with exit code 4
27
+ RUN usermod -l mercury -d /home/mercury -m ubuntu && groupmod -n mercury ubuntu
28
+
29
+ # Copy Bun from official image
30
+ COPY --from=bun-source /usr/local/bin/bun /usr/local/bin/bun
31
+ COPY --from=bun-source /usr/local/bin/bunx /usr/local/bin/bunx
32
+
33
+ # Copy Node.js from official image (avoids flaky nodesource apt repository)
34
+ # npm/npx are symlinks in the upstream image; Docker COPY dereferences single-file
35
+ # symlinks, so recreate them with ln -s after copying node_modules.
36
+ COPY --from=node-source /usr/local/bin/node /usr/local/bin/node
37
+ COPY --from=node-source /usr/local/lib/node_modules /usr/local/lib/node_modules
38
+ COPY --from=node-source /usr/local/include/node /usr/local/include/node
39
+ RUN ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm && \
40
+ ln -s /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx
41
+ ENV HOME="/home/mercury"
42
+ ENV BUN_INSTALL="/home/mercury/.bun"
43
+ ENV PATH="$BUN_INSTALL/bin:/usr/local/bin:$PATH"
44
+
45
+ # Copy Go from official image (avoids curl installer and network flakiness)
46
+ COPY --from=go-source /usr/local/go /usr/local/go
47
+ ENV PATH="/usr/local/go/bin:$PATH"
48
+
49
+ # Install Playwright + Chromium (used by multiple extensions: web-browser, diagrams, charts)
50
+ # HOME=/home/mercury causes playwright to install browsers to /home/mercury/.cache/ms-playwright
51
+ RUN npx playwright install --with-deps chromium
52
+
53
+ # Point puppeteer to Playwright's Chromium so npm packages skip downloading their own
54
+ ENV PUPPETEER_SKIP_DOWNLOAD=true
55
+ RUN ln -sf $(find /home/mercury/.cache/ms-playwright -name chrome -type f | head -1) /usr/local/bin/chromium
56
+ ENV PUPPETEER_EXECUTABLE_PATH=/usr/local/bin/chromium
57
+
58
+ # Allow Chromium to run without sandbox in Docker (required for non-root too)
59
+ RUN echo '{"args":["--no-sandbox"]}' > /home/mercury/.puppeteerrc.json
60
+ ENV CHROMIUM_FLAGS="--no-sandbox"
61
+
62
+ # Install CLIs
63
+ RUN bun add -g @mariozechner/pi-coding-agent@^0.67.2
64
+
65
+ WORKDIR /app
66
+
67
+ COPY container/agent-package.json /app/package.json
68
+ RUN bun install --production
69
+
70
+ # Patch pi: skip thinkingConfig for Gemma models (Google API rejects thinkingBudget for them,
71
+ # but pi marks gemma-4 as reasoning:true and sends thinkingBudget:0 to disable it)
72
+ RUN node <<'EOF'
73
+ const fs = require('fs'), path = require('path');
74
+ function patch(dir) {
75
+ try {
76
+ for (const f of fs.readdirSync(dir)) {
77
+ const p = path.join(dir, f);
78
+ try {
79
+ if (fs.statSync(p).isDirectory()) patch(p);
80
+ else if (f === 'google.js' && p.includes('@mariozechner/pi-ai')) {
81
+ let c = fs.readFileSync(p, 'utf8');
82
+ const noThinking = '&& !model.id.startsWith("gemma")';
83
+ const p1 = 'if (options.thinking?.enabled && model.reasoning) {';
84
+ const p2 = 'else if (model.reasoning && options.thinking && !options.thinking.enabled) {';
85
+ if (!c.includes(noThinking)) {
86
+ c = c.replace(p1, 'if (options.thinking?.enabled && model.reasoning ' + noThinking + ') {');
87
+ c = c.replace(p2, 'else if (model.reasoning && options.thinking && !options.thinking.enabled ' + noThinking + ') {');
88
+ fs.writeFileSync(p, c);
89
+ console.log('Patched:', p);
90
+ }
91
+ }
92
+ } catch(e) {}
93
+ }
94
+ } catch(e) {}
95
+ }
96
+ patch('/home/mercury/.bun');
97
+ patch('/app/node_modules');
98
+ EOF
99
+
100
+ COPY src/agent/container-entry.ts /app/src/agent/container-entry.ts
101
+ COPY src/agent/model-capabilities-core.ts /app/src/agent/model-capabilities-core.ts
102
+ COPY src/agent/pi-failure-class.ts /app/src/agent/pi-failure-class.ts
103
+ COPY src/agent/pi-jsonl-parser.ts /app/src/agent/pi-jsonl-parser.ts
104
+ COPY src/agent/preferences-prompt.ts /app/src/agent/preferences-prompt.ts
105
+ COPY src/cli/mrctl.ts /app/src/cli/mrctl.ts
106
+ COPY src/cli/mrctl-http.ts /app/src/cli/mrctl-http.ts
107
+ COPY src/extensions/reserved.ts /app/src/extensions/reserved.ts
108
+ COPY src/extensions/permission-guard.ts /app/src/extensions/permission-guard.ts
109
+ COPY src/types.ts /app/src/types.ts
110
+ COPY resources/ /app/resources/
111
+ COPY examples/extensions/ /tmp/examples-extensions/
112
+ RUN while IFS= read -r ext || [ -n "$ext" ]; do \
113
+ ext=$(echo "$ext" | xargs); \
114
+ [ -z "$ext" ] && continue; \
115
+ cp -r "/tmp/examples-extensions/$ext" "/app/resources/extensions/$ext"; \
116
+ done < /app/resources/builtin-extensions.txt && \
117
+ rm -rf /tmp/examples-extensions/
118
+
119
+ RUN echo '#!/bin/sh\nbun run /app/src/cli/mrctl.ts "$@"' > /usr/local/bin/mrctl && \
120
+ chmod +x /usr/local/bin/mrctl
121
+
122
+ # Fix ownership of all mercury home dir artifacts before switching user
123
+ RUN chown -R mercury:mercury /home/mercury
124
+
125
+ USER mercury
126
+
127
+ ENTRYPOINT ["bun", "run", "/app/src/agent/container-entry.ts"]
@@ -1,109 +1,109 @@
1
- # syntax=docker/dockerfile:1
2
- # Mercury Agent Container — Base tier
3
- # Base: Microsoft Playwright image (Ubuntu 24.04 noble + Node 22 + Chromium + X11/GL deps preinstalled).
4
- # Adds: Bun, poppler-utils, pandoc, imagemagick, pi-coding-agent, mercury (UID 1000) user.
5
- FROM oven/bun:1 AS bun-source
6
- FROM mcr.microsoft.com/playwright:v1.55.0-noble
7
-
8
- ENV DEBIAN_FRONTEND=noninteractive
9
-
10
- # Document-processing tools. Wrapped in a retry loop — archive.ubuntu.com is periodically flaky
11
- # and a single apt miss shouldn't fail the whole image build.
12
- RUN set -eux; \
13
- for i in 1 2 3 4 5; do \
14
- apt-get update && apt-get install -y --no-install-recommends \
15
- poppler-utils pandoc imagemagick wget \
16
- && break \
17
- || { echo "apt attempt $i/5 failed, sleeping 15s" >&2; apt-get clean; sleep 15; }; \
18
- done; \
19
- rm -rf /var/lib/apt/lists/*
20
-
21
- # Rename the built-in ubuntu user (UID 1000) to mercury.
22
- # Playwright's noble base inherits the ubuntu user at UID/GID 1000; useradd -u 1000
23
- # would fail. (pwuser is at UID 1001 — unused by us.)
24
- RUN usermod -l mercury -d /home/mercury -m ubuntu && groupmod -n mercury ubuntu
25
-
26
- # Copy Bun from official image
27
- COPY --from=bun-source /usr/local/bin/bun /usr/local/bin/bun
28
- COPY --from=bun-source /usr/local/bin/bunx /usr/local/bin/bunx
29
-
30
- ENV HOME="/home/mercury"
31
- ENV BUN_INSTALL="/home/mercury/.bun"
32
- ENV PATH="$BUN_INSTALL/bin:/usr/local/bin:$PATH"
33
-
34
- # Chromium lives in /ms-playwright/chromium-*/chrome-linux/chrome in the Playwright image.
35
- # Symlink to /usr/local/bin/chromium so puppeteer-using npm packages find it.
36
- ENV PUPPETEER_SKIP_DOWNLOAD=true
37
- RUN ln -sf "$(find /ms-playwright -name chrome -type f -executable | head -1)" /usr/local/bin/chromium
38
- ENV PUPPETEER_EXECUTABLE_PATH=/usr/local/bin/chromium
39
-
40
- # --no-sandbox: Chromium can't use its user namespace sandbox inside a container
41
- RUN echo '{"args":["--no-sandbox"]}' > /home/mercury/.puppeteerrc.json
42
- ENV CHROMIUM_FLAGS="--no-sandbox"
43
-
44
- # Install CLIs
45
- RUN bun add -g @mariozechner/pi-coding-agent@^0.67.2
46
-
47
- WORKDIR /app
48
-
49
- COPY container/agent-package.json /app/package.json
50
- RUN bun install --production
51
-
52
- # Patch pi: skip thinkingConfig for Gemma models (Google API rejects thinkingBudget for them,
53
- # but pi marks gemma-4 as reasoning:true and sends thinkingBudget:0 to disable it)
54
- RUN node <<'EOF'
55
- const fs = require('fs'), path = require('path');
56
- function patch(dir) {
57
- try {
58
- for (const f of fs.readdirSync(dir)) {
59
- const p = path.join(dir, f);
60
- try {
61
- if (fs.statSync(p).isDirectory()) patch(p);
62
- else if (f === 'google.js' && p.includes('@mariozechner/pi-ai')) {
63
- let c = fs.readFileSync(p, 'utf8');
64
- const noThinking = '&& !model.id.startsWith("gemma")';
65
- const p1 = 'if (options.thinking?.enabled && model.reasoning) {';
66
- const p2 = 'else if (model.reasoning && options.thinking && !options.thinking.enabled) {';
67
- if (!c.includes(noThinking)) {
68
- c = c.replace(p1, 'if (options.thinking?.enabled && model.reasoning ' + noThinking + ') {');
69
- c = c.replace(p2, 'else if (model.reasoning && options.thinking && !options.thinking.enabled ' + noThinking + ') {');
70
- fs.writeFileSync(p, c);
71
- console.log('Patched:', p);
72
- }
73
- }
74
- } catch(e) {}
75
- }
76
- } catch(e) {}
77
- }
78
- patch('/home/mercury/.bun');
79
- patch('/app/node_modules');
80
- EOF
81
-
82
- COPY src/agent/container-entry.ts /app/src/agent/container-entry.ts
83
- COPY src/agent/model-capabilities-core.ts /app/src/agent/model-capabilities-core.ts
84
- COPY src/agent/pi-failure-class.ts /app/src/agent/pi-failure-class.ts
85
- COPY src/agent/pi-jsonl-parser.ts /app/src/agent/pi-jsonl-parser.ts
86
- COPY src/agent/preferences-prompt.ts /app/src/agent/preferences-prompt.ts
87
- COPY src/cli/mrctl.ts /app/src/cli/mrctl.ts
88
- COPY src/cli/mrctl-http.ts /app/src/cli/mrctl-http.ts
89
- COPY src/extensions/reserved.ts /app/src/extensions/reserved.ts
90
- COPY src/extensions/permission-guard.ts /app/src/extensions/permission-guard.ts
91
- COPY src/types.ts /app/src/types.ts
92
- COPY resources/ /app/resources/
93
- COPY examples/extensions/ /tmp/examples-extensions/
94
- RUN while IFS= read -r ext || [ -n "$ext" ]; do \
95
- ext=$(echo "$ext" | xargs); \
96
- [ -z "$ext" ] && continue; \
97
- cp -r "/tmp/examples-extensions/$ext" "/app/resources/extensions/$ext"; \
98
- done < /app/resources/builtin-extensions.txt && \
99
- rm -rf /tmp/examples-extensions/
100
-
101
- RUN echo '#!/bin/sh\nbun run /app/src/cli/mrctl.ts "$@"' > /usr/local/bin/mrctl && \
102
- chmod +x /usr/local/bin/mrctl
103
-
104
- # Fix ownership of all mercury home dir artifacts before switching user
105
- RUN chown -R mercury:mercury /home/mercury
106
-
107
- USER mercury
108
-
109
- ENTRYPOINT ["bun", "run", "/app/src/agent/container-entry.ts"]
1
+ # syntax=docker/dockerfile:1
2
+ # Mercury Agent Container — Base tier
3
+ # Base: Microsoft Playwright image (Ubuntu 24.04 noble + Node 22 + Chromium + X11/GL deps preinstalled).
4
+ # Adds: Bun, poppler-utils, pandoc, imagemagick, pi-coding-agent, mercury (UID 1000) user.
5
+ FROM oven/bun:1 AS bun-source
6
+ FROM mcr.microsoft.com/playwright:v1.55.0-noble
7
+
8
+ ENV DEBIAN_FRONTEND=noninteractive
9
+
10
+ # Document-processing tools. Wrapped in a retry loop — archive.ubuntu.com is periodically flaky
11
+ # and a single apt miss shouldn't fail the whole image build.
12
+ RUN set -eux; \
13
+ for i in 1 2 3 4 5; do \
14
+ apt-get update && apt-get install -y --no-install-recommends \
15
+ poppler-utils pandoc imagemagick wget \
16
+ && break \
17
+ || { echo "apt attempt $i/5 failed, sleeping 15s" >&2; apt-get clean; sleep 15; }; \
18
+ done; \
19
+ rm -rf /var/lib/apt/lists/*
20
+
21
+ # Rename the built-in ubuntu user (UID 1000) to mercury.
22
+ # Playwright's noble base inherits the ubuntu user at UID/GID 1000; useradd -u 1000
23
+ # would fail. (pwuser is at UID 1001 — unused by us.)
24
+ RUN usermod -l mercury -d /home/mercury -m ubuntu && groupmod -n mercury ubuntu
25
+
26
+ # Copy Bun from official image
27
+ COPY --from=bun-source /usr/local/bin/bun /usr/local/bin/bun
28
+ COPY --from=bun-source /usr/local/bin/bunx /usr/local/bin/bunx
29
+
30
+ ENV HOME="/home/mercury"
31
+ ENV BUN_INSTALL="/home/mercury/.bun"
32
+ ENV PATH="$BUN_INSTALL/bin:/usr/local/bin:$PATH"
33
+
34
+ # Chromium lives in /ms-playwright/chromium-*/chrome-linux/chrome in the Playwright image.
35
+ # Symlink to /usr/local/bin/chromium so puppeteer-using npm packages find it.
36
+ ENV PUPPETEER_SKIP_DOWNLOAD=true
37
+ RUN ln -sf "$(find /ms-playwright -name chrome -type f -executable | head -1)" /usr/local/bin/chromium
38
+ ENV PUPPETEER_EXECUTABLE_PATH=/usr/local/bin/chromium
39
+
40
+ # --no-sandbox: Chromium can't use its user namespace sandbox inside a container
41
+ RUN echo '{"args":["--no-sandbox"]}' > /home/mercury/.puppeteerrc.json
42
+ ENV CHROMIUM_FLAGS="--no-sandbox"
43
+
44
+ # Install CLIs
45
+ RUN bun add -g @mariozechner/pi-coding-agent@^0.67.2
46
+
47
+ WORKDIR /app
48
+
49
+ COPY container/agent-package.json /app/package.json
50
+ RUN bun install --production
51
+
52
+ # Patch pi: skip thinkingConfig for Gemma models (Google API rejects thinkingBudget for them,
53
+ # but pi marks gemma-4 as reasoning:true and sends thinkingBudget:0 to disable it)
54
+ RUN node <<'EOF'
55
+ const fs = require('fs'), path = require('path');
56
+ function patch(dir) {
57
+ try {
58
+ for (const f of fs.readdirSync(dir)) {
59
+ const p = path.join(dir, f);
60
+ try {
61
+ if (fs.statSync(p).isDirectory()) patch(p);
62
+ else if (f === 'google.js' && p.includes('@mariozechner/pi-ai')) {
63
+ let c = fs.readFileSync(p, 'utf8');
64
+ const noThinking = '&& !model.id.startsWith("gemma")';
65
+ const p1 = 'if (options.thinking?.enabled && model.reasoning) {';
66
+ const p2 = 'else if (model.reasoning && options.thinking && !options.thinking.enabled) {';
67
+ if (!c.includes(noThinking)) {
68
+ c = c.replace(p1, 'if (options.thinking?.enabled && model.reasoning ' + noThinking + ') {');
69
+ c = c.replace(p2, 'else if (model.reasoning && options.thinking && !options.thinking.enabled ' + noThinking + ') {');
70
+ fs.writeFileSync(p, c);
71
+ console.log('Patched:', p);
72
+ }
73
+ }
74
+ } catch(e) {}
75
+ }
76
+ } catch(e) {}
77
+ }
78
+ patch('/home/mercury/.bun');
79
+ patch('/app/node_modules');
80
+ EOF
81
+
82
+ COPY src/agent/container-entry.ts /app/src/agent/container-entry.ts
83
+ COPY src/agent/model-capabilities-core.ts /app/src/agent/model-capabilities-core.ts
84
+ COPY src/agent/pi-failure-class.ts /app/src/agent/pi-failure-class.ts
85
+ COPY src/agent/pi-jsonl-parser.ts /app/src/agent/pi-jsonl-parser.ts
86
+ COPY src/agent/preferences-prompt.ts /app/src/agent/preferences-prompt.ts
87
+ COPY src/cli/mrctl.ts /app/src/cli/mrctl.ts
88
+ COPY src/cli/mrctl-http.ts /app/src/cli/mrctl-http.ts
89
+ COPY src/extensions/reserved.ts /app/src/extensions/reserved.ts
90
+ COPY src/extensions/permission-guard.ts /app/src/extensions/permission-guard.ts
91
+ COPY src/types.ts /app/src/types.ts
92
+ COPY resources/ /app/resources/
93
+ COPY examples/extensions/ /tmp/examples-extensions/
94
+ RUN while IFS= read -r ext || [ -n "$ext" ]; do \
95
+ ext=$(echo "$ext" | xargs); \
96
+ [ -z "$ext" ] && continue; \
97
+ cp -r "/tmp/examples-extensions/$ext" "/app/resources/extensions/$ext"; \
98
+ done < /app/resources/builtin-extensions.txt && \
99
+ rm -rf /tmp/examples-extensions/
100
+
101
+ RUN echo '#!/bin/sh\nbun run /app/src/cli/mrctl.ts "$@"' > /usr/local/bin/mrctl && \
102
+ chmod +x /usr/local/bin/mrctl
103
+
104
+ # Fix ownership of all mercury home dir artifacts before switching user
105
+ RUN chown -R mercury:mercury /home/mercury
106
+
107
+ USER mercury
108
+
109
+ ENTRYPOINT ["bun", "run", "/app/src/agent/container-entry.ts"]
@@ -1,17 +1,17 @@
1
- # syntax=docker/dockerfile:1
2
- # Mercury Agent Container — Power tier
3
- # Extends Base with: python3 + pip + venv, build-essential, jq, ffmpeg, bubblewrap
4
- # The patch script, mrctl, and entrypoint are all inherited from Base — not duplicated here.
5
- ARG BASE_TAG
6
- FROM ghcr.io/avishai-tsabari/mercury-agent:${BASE_TAG}-base
7
-
8
- USER root
9
- RUN apt-get update && apt-get install -y --no-install-recommends \
10
- python3 python3-pip python3-venv build-essential \
11
- jq \
12
- ffmpeg \
13
- # Sandboxing: bubblewrap for defense-in-depth in runc mode.
14
- # Not used when CONTAINER_RUNTIME=runsc (gVisor handles isolation at the syscall boundary).
15
- bubblewrap \
16
- && rm -rf /var/lib/apt/lists/*
17
- USER mercury
1
+ # syntax=docker/dockerfile:1
2
+ # Mercury Agent Container — Power tier
3
+ # Extends Base with: python3 + pip + venv, build-essential, jq, ffmpeg, bubblewrap
4
+ # The patch script, mrctl, and entrypoint are all inherited from Base — not duplicated here.
5
+ ARG BASE_TAG
6
+ FROM ghcr.io/avishai-tsabari/mercury-agent:${BASE_TAG}-base
7
+
8
+ USER root
9
+ RUN apt-get update && apt-get install -y --no-install-recommends \
10
+ python3 python3-pip python3-venv build-essential \
11
+ jq \
12
+ ffmpeg \
13
+ # Sandboxing: bubblewrap for defense-in-depth in runc mode.
14
+ # Not used when CONTAINER_RUNTIME=runsc (gVisor handles isolation at the syscall boundary).
15
+ bubblewrap \
16
+ && rm -rf /var/lib/apt/lists/*
17
+ USER mercury
@@ -1,8 +1,8 @@
1
- {
2
- "name": "mercury-agent-app",
3
- "private": true,
4
- "type": "module",
5
- "dependencies": {
6
- "@earendil-works/pi-coding-agent": "~0.79.6"
7
- }
8
- }
1
+ {
2
+ "name": "mercury-agent-app",
3
+ "private": true,
4
+ "type": "module",
5
+ "dependencies": {
6
+ "@earendil-works/pi-coding-agent": "~0.79.6"
7
+ }
8
+ }
@@ -1,54 +1,54 @@
1
- #!/bin/bash
2
- # Build the Mercury agent container images
3
- set -e
4
-
5
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
- PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
7
- cd "$PROJECT_ROOT"
8
-
9
- IMAGE_NAME="mercury-agent"
10
-
11
- # Parse arguments
12
- BUILD_ALL=false
13
- BUILD_LATEST=false
14
- BUILD_MINIMAL=false
15
-
16
- if [ $# -eq 0 ]; then
17
- BUILD_LATEST=true
18
- elif [ "$1" = "all" ]; then
19
- BUILD_ALL=true
20
- elif [ "$1" = "latest" ]; then
21
- BUILD_LATEST=true
22
- elif [ "$1" = "minimal" ]; then
23
- BUILD_MINIMAL=true
24
- else
25
- echo "Usage: $0 [all|latest|minimal]"
26
- echo ""
27
- echo "Presets:"
28
- echo " latest Full devcontainer with Node, Python, Go, git (~2.8GB)"
29
- echo " minimal Bun + pi + browser only (~1.9GB)"
30
- echo " all Build both presets"
31
- echo ""
32
- echo "Default: latest"
33
- exit 1
34
- fi
35
-
36
- if [ "$BUILD_ALL" = true ] || [ "$BUILD_LATEST" = true ]; then
37
- echo "Building ${IMAGE_NAME}:latest (full devcontainer)..."
38
- docker build -f container/Dockerfile -t "${IMAGE_NAME}:latest" .
39
- echo "✓ Built ${IMAGE_NAME}:latest"
40
- echo ""
41
- fi
42
-
43
- if [ "$BUILD_ALL" = true ] || [ "$BUILD_MINIMAL" = true ]; then
44
- echo "Building ${IMAGE_NAME}:minimal (bun-only)..."
45
- docker build -f container/Dockerfile.minimal -t "${IMAGE_NAME}:minimal" .
46
- echo "✓ Built ${IMAGE_NAME}:minimal"
47
- echo ""
48
- fi
49
-
50
- echo "Build complete!"
51
- if [ "$BUILD_ALL" = true ]; then
52
- echo " ${IMAGE_NAME}:latest - Full devcontainer (~2.8GB)"
53
- echo " ${IMAGE_NAME}:minimal - Bun + pi + browser (~1.9GB)"
54
- fi
1
+ #!/bin/bash
2
+ # Build the Mercury agent container images
3
+ set -e
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
+ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
7
+ cd "$PROJECT_ROOT"
8
+
9
+ IMAGE_NAME="mercury-agent"
10
+
11
+ # Parse arguments
12
+ BUILD_ALL=false
13
+ BUILD_LATEST=false
14
+ BUILD_MINIMAL=false
15
+
16
+ if [ $# -eq 0 ]; then
17
+ BUILD_LATEST=true
18
+ elif [ "$1" = "all" ]; then
19
+ BUILD_ALL=true
20
+ elif [ "$1" = "latest" ]; then
21
+ BUILD_LATEST=true
22
+ elif [ "$1" = "minimal" ]; then
23
+ BUILD_MINIMAL=true
24
+ else
25
+ echo "Usage: $0 [all|latest|minimal]"
26
+ echo ""
27
+ echo "Presets:"
28
+ echo " latest Full devcontainer with Node, Python, Go, git (~2.8GB)"
29
+ echo " minimal Bun + pi + browser only (~1.9GB)"
30
+ echo " all Build both presets"
31
+ echo ""
32
+ echo "Default: latest"
33
+ exit 1
34
+ fi
35
+
36
+ if [ "$BUILD_ALL" = true ] || [ "$BUILD_LATEST" = true ]; then
37
+ echo "Building ${IMAGE_NAME}:latest (full devcontainer)..."
38
+ docker build -f container/Dockerfile -t "${IMAGE_NAME}:latest" .
39
+ echo "✓ Built ${IMAGE_NAME}:latest"
40
+ echo ""
41
+ fi
42
+
43
+ if [ "$BUILD_ALL" = true ] || [ "$BUILD_MINIMAL" = true ]; then
44
+ echo "Building ${IMAGE_NAME}:minimal (bun-only)..."
45
+ docker build -f container/Dockerfile.minimal -t "${IMAGE_NAME}:minimal" .
46
+ echo "✓ Built ${IMAGE_NAME}:minimal"
47
+ echo ""
48
+ fi
49
+
50
+ echo "Build complete!"
51
+ if [ "$BUILD_ALL" = true ]; then
52
+ echo " ${IMAGE_NAME}:latest - Full devcontainer (~2.8GB)"
53
+ echo " ${IMAGE_NAME}:minimal - Bun + pi + browser (~1.9GB)"
54
+ fi