Skip to content

Commit 7c7d24d

Browse files
Expand devcontainer with full Soroban/K toolchain
Adds Rust (wasm32 targets), Stellar CLI, uv, Nix, and the K framework via kup/komet so the debugger pipeline runs end-to-end inside the container. Includes install-komet-node.sh which builds the kdist semantics and aligns pyk to the installed kompile version. Also renames the container to simbolik-komet and adds rust-analyzer. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d340d2b commit 7c7d24d

3 files changed

Lines changed: 145 additions & 3 deletions

File tree

.devcontainer/Dockerfile

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,84 @@
11
FROM node:22-bookworm
22

3+
# --- System packages -------------------------------------------------------
4+
# git/sudo/less: base dev convenience. libdbus-1-3: required by the Stellar CLI.
5+
# build-essential/clang/pkg-config/libssl: needed to compile Rust contracts and
6+
# any from-source crates. curl/xz/jq: used by the toolchain installers below.
37
RUN apt-get update && apt-get install -y --no-install-recommends \
48
git \
59
sudo \
610
ca-certificates \
711
less \
12+
curl \
13+
xz-utils \
14+
jq \
15+
build-essential \
16+
clang \
17+
pkg-config \
18+
libssl-dev \
19+
libdbus-1-3 \
820
&& rm -rf /var/lib/apt/lists/*
921

1022
# Give the default `node` user passwordless sudo (convenient inside the container)
1123
RUN echo "node ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/node \
1224
&& chmod 0440 /etc/sudoers.d/node
1325

14-
# Install Claude Code globally so `claude` is on PATH for the node user
26+
# Bootstrap Claude Code via npm so the `claude` CLI exists, then switch to the
27+
# native installer as the node user. The native install lives under ~/.local/bin,
28+
# which node owns, so auto-updates work without sudo or a writable npm prefix.
1529
RUN npm install -g @anthropic-ai/claude-code
1630

31+
# --- Stellar CLI (prebuilt) ------------------------------------------------
32+
# Used by the debugger to build Soroban contracts (`stellar contract build`).
33+
ARG STELLAR_CLI_VERSION=26.1.0
34+
RUN curl -sSL \
35+
"https://github.com/stellar/stellar-cli/releases/download/v${STELLAR_CLI_VERSION}/stellar-cli-${STELLAR_CLI_VERSION}-x86_64-unknown-linux-gnu.tar.gz" \
36+
| tar xz -C /usr/local/bin stellar \
37+
&& stellar --version
38+
39+
# --- Nix prep --------------------------------------------------------------
40+
# Single-user Nix is installed under /nix as the `node` user (no systemd in the
41+
# container). Pre-create /nix with node ownership so the installer can write it.
42+
RUN mkdir -p /nix && chown -R node /nix
43+
1744
USER node
1845
WORKDIR /workspace
46+
47+
RUN claude install
48+
49+
# --- Rust toolchain (Soroban contracts) ------------------------------------
50+
ENV RUSTUP_HOME=/home/node/.rustup \
51+
CARGO_HOME=/home/node/.cargo
52+
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
53+
| sh -s -- -y --profile minimal \
54+
&& /home/node/.cargo/bin/rustup target add wasm32v1-none wasm32-unknown-unknown
55+
56+
# --- uv (Python package manager for komet-node) ----------------------------
57+
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
58+
59+
# --- Nix + kup + komet semantics -------------------------------------------
60+
# komet-node executes contracts via the K-based `komet` semantics. We install
61+
# the K toolchain through Runtime Verification's `kup` (Nix-based), pulling
62+
# prebuilt binaries from RV's binary cache rather than compiling from source.
63+
ENV NIX_CONFIG="experimental-features = nix-command flakes"
64+
RUN curl -L https://nixos.org/nix/install | sh -s -- --no-daemon --yes
65+
ENV PATH="/home/node/.nix-profile/bin:/home/node/.local/bin:/home/node/.cargo/bin:${PATH}"
66+
# Mark `node` as a trusted Nix user and pre-register RV's binary caches. kup
67+
# otherwise prompts interactively to add these substituters, and the build dies
68+
# with EOFError on input() since stdin is closed. When the user is trusted, kup
69+
# skips the prompt and passes the caches as flags instead. Keys are kup's own.
70+
RUN sudo mkdir -p /etc/nix \
71+
&& printf '%s\n' \
72+
'trusted-users = root node' \
73+
'extra-substituters = https://k-framework.cachix.org https://k-framework-binary.cachix.org' \
74+
'extra-trusted-public-keys = k-framework.cachix.org-1:jeyMXB2h28gpNRjuVkehg+zLj62ma1RnyyopA/20yFE= k-framework-binary.cachix.org-1:pJedQ8iG19BW3v/DMMmiRVtwRBGO3fyMv2Ws0OpBADs=' \
75+
| sudo tee -a /etc/nix/nix.conf
76+
RUN curl -L https://kframework.org/install | bash \
77+
&& kup install komet
78+
79+
# --- komet-node (local Stellar testnet on K semantics) ---------------------
80+
# Installed into a dedicated venv; exposes `python -m komet_node`.
81+
# (Finalized after live verification — see scripts/install-komet-node.sh.)
82+
ENV KOMET_NODE_VENV=/home/node/.komet-node
83+
COPY --chown=node:node install-komet-node.sh /tmp/install-komet-node.sh
84+
RUN bash /tmp/install-komet-node.sh

.devcontainer/devcontainer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "longlight",
2+
"name": "simbolik-komet",
33
"build": {
44
"dockerfile": "Dockerfile"
55
},
@@ -16,7 +16,8 @@
1616
"customizations": {
1717
"vscode": {
1818
"extensions": [
19-
"anthropic.claude-code"
19+
"anthropic.claude-code",
20+
"rust-lang.rust-analyzer"
2021
]
2122
}
2223
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Installs komet-node (the local Stellar testnet on K semantics) into a
4+
# dedicated uv-managed virtualenv and builds its kompiled semantics.
5+
#
6+
# Prerequisites (provided by the Dockerfile): uv on PATH, and the `komet` /
7+
# K toolchain installed via kup (so `kdist`/`kompile` are available).
8+
#
9+
# Result: `source $KOMET_NODE_VENV/bin/activate` then
10+
# `python -m komet_node --trace` runs the node.
11+
set -euo pipefail
12+
13+
export PATH="/home/node/.nix-profile/bin:/home/node/.local/bin:${PATH}"
14+
15+
VENV="${KOMET_NODE_VENV:-/home/node/.komet-node}"
16+
KOMET_NODE_REF="${KOMET_NODE_REF:-main}"
17+
18+
echo ">>> Creating komet-node venv at ${VENV}"
19+
uv venv --python 3.10 "${VENV}"
20+
# shellcheck disable=SC1091
21+
source "${VENV}/bin/activate"
22+
23+
echo ">>> Installing komet-node from git (@${KOMET_NODE_REF})"
24+
uv pip install "git+https://github.com/runtimeverification/komet-node.git@${KOMET_NODE_REF}"
25+
26+
echo ">>> Building komet-node kdist semantics"
27+
# Builds the node semantics on top of the komet/KWasm semantics. This is the
28+
# slow step; it reuses prebuilt komet artifacts from the kup install.
29+
#
30+
# kup installs `komet` as a makeWrapper script that injects the K binaries
31+
# (kompile, krun, ...) onto komet's *own* PATH only — they aren't exposed
32+
# globally. kdist invokes `kompile` directly, so locate K's bin dir from the
33+
# komet wrapper and put it on PATH (grep -a so it works whether the wrapper is
34+
# a shell script or a compiled binary wrapper; the store paths are embedded in
35+
# both).
36+
#
37+
# NOTE: reference the kup wrapper by its explicit nix-profile path, NOT via
38+
# `command -v komet`. The activated venv installs its own `komet` console
39+
# script that shadows the wrapper but contains no /nix/store paths.
40+
KUP_KOMET="${HOME}/.nix-profile/bin/komet"
41+
if ! command -v kompile >/dev/null 2>&1; then
42+
komet_wrapper="$(readlink -f "${KUP_KOMET}")"
43+
for d in $(grep -aoE "/nix/store/[^\"' :]+/bin" "${komet_wrapper}" | sort -u); do
44+
if [ -x "${d}/kompile" ]; then
45+
export PATH="${d}:${PATH}"
46+
break
47+
fi
48+
done
49+
fi
50+
command -v kompile >/dev/null 2>&1 || {
51+
echo "ERROR: could not locate kompile (K framework) via the komet wrapper" >&2
52+
exit 1
53+
}
54+
55+
# Align the venv's pyk to the kompile that will build the kdist targets. The
56+
# komet-node wheel pins `kframework<7.1.321` (kast JSON format v3), but the
57+
# kup-installed K binaries are newer and emit a later format. pyk validates the
58+
# kast version when it reads `compiled.json`, so a pyk older than the kompile
59+
# that produced the artifact aborts with `Invalid version: N` and the node dies
60+
# on its first request. The invariant is "pyk must match kompile", so we install
61+
# the matching kframework version, overriding the wheel's upper-bound pin.
62+
K_VERSION="$(kompile --version | sed -n 's/^K version:[[:space:]]*v//p')"
63+
echo ">>> Aligning pyk to K ${K_VERSION}"
64+
uv pip install "kframework==${K_VERSION}"
65+
66+
echo ">>> Building kdist semantics"
67+
# The node imports the four soroban-semantics definitions (llvm, llvm-tracing,
68+
# llvm-library, haskell) at module load time, plus komet-node's own simbolik
69+
# target. Building only 'komet-node.*' leaves the soroban-semantics targets
70+
# unbuilt, so the server crashes on import with
71+
# `Target undefined or not built: soroban-semantics.llvm`.
72+
kdist build 'soroban-semantics.*' 'komet-node.*'
73+
74+
echo ">>> komet-node install complete"
75+
python -m komet_node --help >/dev/null 2>&1 || true

0 commit comments

Comments
 (0)