mercury-agent 0.4.28 → 0.5.1

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 (122) hide show
  1. package/README.md +451 -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/ARCHITECTURE.md +4 -0
  8. package/docs/ROADMAP.md +4 -5
  9. package/docs/{backlog/applicative-profiles.md → archive/applicative-profiles/2026-07-01-applicative-profiles.md} +29 -18
  10. package/docs/{backlog/caller-bound-capability-token.md → archive/applicative-profiles/2026-07-01-caller-bound-capability-token.md} +15 -11
  11. package/docs/archive/summarization/2026-07-02-recent-dev-summary.md +71 -0
  12. package/docs/auth/dashboard.md +28 -28
  13. package/docs/auth/overview.md +109 -109
  14. package/docs/auth/whatsapp.md +173 -173
  15. package/docs/authoring-profiles.md +174 -0
  16. package/docs/configuration.md +54 -54
  17. package/docs/container-lifecycle.md +349 -349
  18. package/docs/{bugs/bwrap-privileged-linux-docker.md → debug/major/2026-07-02-bwrap-privileged-linux-docker.md} +21 -1
  19. package/docs/{bugs/e2big-prompt-delivery-fix.md → debug/major/2026-07-02-e2big-prompt-delivery-fix.md} +27 -1
  20. package/docs/{bugs/registry-pull-no-local-fallback.md → debug/major/2026-07-02-registry-pull-no-local-fallback.md} +27 -1
  21. package/docs/debug/summarization/2026-07-02-common-bug-patterns.md +72 -0
  22. package/docs/deployment.md +199 -199
  23. package/docs/extensions.md +375 -375
  24. package/docs/graceful-shutdown.md +62 -62
  25. package/docs/kb-distillation.md +77 -77
  26. package/docs/media/overview.md +140 -140
  27. package/docs/media/whatsapp.md +171 -171
  28. package/docs/memory.md +137 -137
  29. package/docs/permissions.md +217 -217
  30. package/docs/pipeline.md +228 -228
  31. package/docs/prd-chat-memory.md +76 -76
  32. package/docs/prd-config-load.md +82 -82
  33. package/docs/rate-limiting.md +229 -229
  34. package/docs/scheduler.md +288 -288
  35. package/docs/setup-discord.md +100 -100
  36. package/docs/setup-slack.md +119 -119
  37. package/docs/setup-whatsapp.md +94 -94
  38. package/docs/subagents.md +166 -166
  39. package/docs/web-search.md +62 -62
  40. package/examples/extensions/README.md +12 -12
  41. package/examples/extensions/charts/index.ts +13 -13
  42. package/examples/extensions/charts/skill/SKILL.md +98 -98
  43. package/examples/extensions/gws/README.md +52 -52
  44. package/examples/extensions/gws/skill/SKILL.md +57 -57
  45. package/examples/extensions/gws/skill/references/calendar.md +101 -101
  46. package/examples/extensions/gws/skill/references/docs.md +65 -65
  47. package/examples/extensions/gws/skill/references/drive.md +79 -79
  48. package/examples/extensions/gws/skill/references/gmail.md +85 -85
  49. package/examples/extensions/gws/skill/references/sheets.md +60 -60
  50. package/examples/extensions/napkin/skill/SKILL.md +728 -728
  51. package/examples/extensions/pdf/skill/LICENSE.txt +30 -30
  52. package/examples/extensions/pdf/skill/SKILL.md +314 -314
  53. package/examples/extensions/pdf/skill/forms.md +294 -294
  54. package/examples/extensions/pdf/skill/reference.md +611 -611
  55. package/examples/extensions/pdf/skill/scripts/check_bounding_boxes.py +65 -65
  56. package/examples/extensions/pdf/skill/scripts/check_fillable_fields.py +11 -11
  57. package/examples/extensions/pdf/skill/scripts/convert_pdf_to_images.py +33 -33
  58. package/examples/extensions/pdf/skill/scripts/create_validation_image.py +37 -37
  59. package/examples/extensions/pdf/skill/scripts/extract_form_field_info.py +122 -122
  60. package/examples/extensions/pdf/skill/scripts/extract_form_structure.py +115 -115
  61. package/examples/extensions/pdf/skill/scripts/fill_fillable_fields.py +98 -98
  62. package/examples/extensions/pdf/skill/scripts/fill_pdf_form_with_annotations.py +107 -107
  63. package/examples/extensions/permission-guard/index.ts +65 -65
  64. package/examples/extensions/pinchtab/skill/SKILL.md +224 -224
  65. package/examples/extensions/pinchtab/skill/TRUST.md +69 -69
  66. package/examples/extensions/pinchtab/skill/references/api.md +297 -297
  67. package/examples/extensions/pinchtab/skill/references/env.md +45 -45
  68. package/examples/extensions/pinchtab/skill/references/profiles.md +107 -107
  69. package/examples/extensions/tradestation/host/refresh.ts +102 -102
  70. package/examples/extensions/tradestation/index.ts +153 -153
  71. package/examples/extensions/tradestation/skill/SKILL.md +67 -67
  72. package/examples/extensions/voice-synth/index.ts +94 -94
  73. package/examples/extensions/voice-synth/skill/SKILL.md +38 -38
  74. package/examples/extensions/voice-transcribe/requirements.txt +8 -8
  75. package/examples/extensions/voice-transcribe/scripts/transcribe.py +179 -179
  76. package/examples/extensions/voice-transcribe/skill/SKILL.md +53 -53
  77. package/examples/extensions/yahoo-mail/cli/package.json +13 -13
  78. package/examples/extensions/yahoo-mail/skill/SKILL.md +78 -78
  79. package/package.json +106 -106
  80. package/resources/agents/explore.md +50 -50
  81. package/resources/agents/worker.md +24 -24
  82. package/resources/connection-env-vars.json +25 -25
  83. package/resources/pi-extensions/subagent/agents.ts +126 -126
  84. package/resources/pi-extensions/subagent/index.ts +964 -964
  85. package/resources/profiles/coding/AGENTS.md +43 -43
  86. package/resources/profiles/coding/mercury-profile.yaml +15 -15
  87. package/resources/profiles/general/AGENTS.md +31 -31
  88. package/resources/profiles/general/mercury-profile.yaml +15 -15
  89. package/resources/profiles/research/AGENTS.md +40 -40
  90. package/resources/profiles/research/mercury-profile.yaml +15 -15
  91. package/resources/skills/config/SKILL.md +25 -25
  92. package/resources/skills/context/SKILL.md +33 -33
  93. package/resources/skills/conversation-recap/SKILL.md +19 -19
  94. package/resources/skills/mutes/SKILL.md +31 -31
  95. package/resources/skills/permissions/SKILL.md +19 -19
  96. package/resources/skills/preferences/SKILL.md +31 -31
  97. package/resources/skills/recall/SKILL.md +24 -24
  98. package/resources/skills/roles/SKILL.md +18 -18
  99. package/resources/skills/spaces/SKILL.md +18 -18
  100. package/resources/skills/tasks/SKILL.md +45 -45
  101. package/resources/templates/AGENTS.md +157 -157
  102. package/resources/templates/env.template +38 -38
  103. package/resources/templates/mercury.example.yaml +15 -0
  104. package/src/agent/container-runner.ts +23 -0
  105. package/src/cli/mercury.ts +38 -6
  106. package/src/cli/mrctl.ts +25 -0
  107. package/src/config-file.ts +3 -0
  108. package/src/config.ts +15 -0
  109. package/src/core/api.ts +23 -3
  110. package/src/core/caller-token.ts +101 -0
  111. package/src/core/permissions.ts +37 -5
  112. package/src/core/profiles.ts +110 -84
  113. package/src/core/routes/capability.ts +70 -0
  114. package/src/core/routes/index.ts +1 -0
  115. package/src/core/runtime.ts +14 -0
  116. package/src/dashboard/index.html +729 -729
  117. package/src/extensions/api.ts +21 -0
  118. package/src/extensions/loader.ts +15 -0
  119. package/src/extensions/types.ts +55 -0
  120. package/src/main.ts +19 -0
  121. package/docs/pending-updates/dm-auto-space.md +0 -15
  122. /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