Files
molecule-ai-workspace-templ…/Dockerfile.platform-agent
core-devops 5825649a49
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 2s
CI / Template validation (static) (push) Successful in 4s
CI / Adapter unit tests (pull_request) Successful in 6s
CI / Adapter unit tests (push) Successful in 5s
CI / Template validation (static) (pull_request) Successful in 8s
verify-providers-projection / Regenerate projection, fail on drift, assert registry ⊆ template (pull_request) Successful in 1m17s
CI / Template validation (runtime) (push) Successful in 1m58s
CI / T4 tier-4 conformance (live) (push) Successful in 1m57s
CI / validate (push) Successful in 2s
CI / Template validation (runtime) (pull_request) Successful in 2m3s
CI / T4 tier-4 conformance (live) (pull_request) Successful in 2m6s
CI / validate (pull_request) Successful in 1s
bump: @molecule-ai/mcp-server 1.6.0 -> 1.6.1 (management-mode startup fix)
1.6.0 died at startup in management mode (duplicate create_request,
mcp-server#63) — the image smoke gate correctly refused to publish it.
1.6.1 removes the duplicate; create_approval + create_request both serve
from the composed registry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:29:35 -07:00

78 lines
4.1 KiB
Docker

# molecule-platform-agent image
# RFC: molecule-core docs/design/rfc-platform-agent.md §5.7
#
# A dedicated image, FROM this repo's workspace-template-claude-code image, that
# bakes in the org-management MCP (@molecule-ai/mcp-server) so the org-level
# platform agent can drive the org alongside the always-on a2a MCP.
#
# Built in THIS repo (not molecule-ci) so it reuses the existing publish
# pipeline's ECR credentials, publish runners, and pin-promote — NO new secret.
# The MCP is pulled from the org's Gitea npm registry, which serves the package
# anonymously, so the build needs no token or cross-repo checkout either.
#
# Keeps the org-admin MCP OUT of ordinary workspace images (security hygiene):
# only this image installs it; ordinary workspaces declare no extra mcp_servers.
# Pin to a specific workspace-template-claude-code tag at build time via
# --build-arg BASE_IMAGE=...:sha-<7> (the publish workflow passes the sha it just
# pushed). Defaults to :latest for local builds.
ARG BASE_IMAGE=153263036946.dkr.ecr.us-east-2.amazonaws.com/molecule-ai/workspace-template-claude-code:latest
FROM ${BASE_IMAGE}
# Version of @molecule-ai/mcp-server to bake (pin for reproducible builds).
ARG MCP_VERSION=1.6.1
USER root
# Pin Node 20. The debian-slim base apt-installs `nodejs` (Node 18); the org
# MCP's @modelcontextprotocol/sdk requires >=20. Install Node 20 from NodeSource,
# replacing the apt nodejs so `node` resolves to 20 for both claude-code and the
# baked MCP.
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends ca-certificates curl gnupg; \
mkdir -p /etc/apt/keyrings; \
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
| gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg; \
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" \
> /etc/apt/sources.list.d/nodesource.list; \
apt-get update; \
apt-get install -y --no-install-recommends nodejs; \
node --version | grep -E '^v20\.'; \
rm -rf /var/lib/apt/lists/*
# Install the org-management MCP globally from the org Gitea npm registry
# (anonymous read — no auth). The package's OWN bin name (molecule-mcp)
# COLLIDES with the runtime wheel's Python a2a inbox bridge at
# /usr/local/bin/molecule-mcp, which wins on PATH — so the concierge config
# references the UNAMBIGUOUS `molecule-platform-mcp` symlink instead:
# `mcp_servers: [{name: platform, command: molecule-platform-mcp,
# env: {MOLECULE_MCP_MODE: management}}]`
# (core: conciergeMCPServersBlock). The symlink targets the package entry
# directly so it cannot be shadowed by any future bin-name squatter.
RUN set -eux; \
printf '@molecule-ai:registry=https://git.moleculesai.app/api/packages/molecule-ai/npm/\n' > /etc/npmrc; \
npm install -g --userconfig /etc/npmrc "@molecule-ai/mcp-server@${MCP_VERSION}"; \
chmod +x /usr/lib/node_modules/@molecule-ai/mcp-server/dist/index.js; \
ln -sf /usr/lib/node_modules/@molecule-ai/mcp-server/dist/index.js /usr/local/bin/molecule-platform-mcp; \
command -v molecule-platform-mcp
# Self-contain the adapter-module import path. The runtime boots via its console-script
# entrypoint, which does NOT put the working dir on sys.path — so the adapter
# module at the image's working directory is unimportable unless the working
# directory is on PYTHONPATH. Ordinary workspace images get this from the
# platform's container environment; THIS image is launched by a different
# runner that does not inject it, so the dedicated platform-agent image must
# set PYTHONPATH itself, or the runtime fails to start when the import fails.
# Putting the working directory first on PYTHONPATH also keeps the local
# modules ahead of any same-named modules under site-packages (see the base
# Dockerfile's COPY notes).
ENV PYTHONPATH=/app
# Marker so the runtime/provisioner can assert it is on the platform-agent image
# (and not an ordinary workspace image) before declaring the platform MCP.
ENV MOLECULE_PLATFORM_AGENT_IMAGE_BAKED=1
# Return to the agent uid the base image runs as.
USER agent