Skip to content

Commit a369b25

Browse files
authored
feat: ✨ enhance Docker image with engram, aleph, and shell env setup (#1)
2 parents c5d6caf + fc728b7 commit a369b25

File tree

3 files changed

+140
-36
lines changed

3 files changed

+140
-36
lines changed

.github/workflows/pr-checks.yml

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,19 @@
22
name: Pull Request validation
33

44
on:
5-
- pull_request
5+
pull_request:
6+
types:
7+
- opened
8+
- reopened
9+
- synchronize
10+
- ready_for_review
11+
12+
concurrency:
13+
group: pr-validation-${{ github.event.pull_request.number || github.ref }}
14+
cancel-in-progress: true
15+
16+
permissions:
17+
contents: read
618

719
jobs:
820
pre-commit:
@@ -11,20 +23,23 @@ jobs:
1123
- name: Checkout code
1224
id: checkout
1325
uses: actions/checkout@v5
26+
with:
27+
fetch-depth: 0
28+
29+
- name: Detect changed files
30+
id: changed-files
31+
uses: tj-actions/changed-files@v46
32+
with:
33+
files: |
34+
Dockerfile
1435
15-
- name: Set up Python
16-
id: setup-python
17-
uses: actions/setup-python@v5
36+
- name: Setup toolchain with mise
37+
uses: jdx/mise-action@v2
1838

19-
- name: Run pre-commit checks
20-
id: pre-commit
21-
uses: cloudposse/github-action-pre-commit@v4.0.0
39+
- name: Run prek hooks
40+
run: prek run --all-files --show-diff-on-failure --color=always
2241

2342
- name: Build Docker image if Dockerfile changed
43+
if: steps.changed-files.outputs.any_changed == 'true'
2444
run: |
25-
if git diff --name-only origin/${{ github.base_ref }} | grep -q '^Dockerfile$'; then
26-
echo "Dockerfile changed — building image..."
27-
docker build -t opencode-cli-pr:latest .
28-
else
29-
echo "Dockerfile not changed — skipping build."
30-
fi
45+
docker build -t opencode-cli-pr:latest .

Dockerfile

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,22 +62,27 @@ else
6262
fi
6363
EOF
6464

65-
chown -Rh bun:bun "$(echo ~bun)"
66-
6765
FOE
6866

6967
COPY --chmod=0555 entrypoint.sh /entrypoint.sh
7068

7169
ARG OPENCODE_VERSION=latest
70+
ARG AZURE_FOUNDRY_PROVIDER_VERSION=0.2.0
71+
ARG ENGRAM_VERSION=v1.9.1
72+
7273
ENV OPENCODE_CONFIG_DIR=/etc/opencode
74+
ENV OPENCODE_EXPERIMENTAL=1
75+
ENV ENGRAM_DATA_DIR=/home/bun/.local/share/opencode/engram
7376

7477
# hadolint ignore=DL3003,SC2164
7578
RUN <<'FOE'
7679

7780
export BUN_INSTALL=/usr/local/bun
7881
export PROVIDER_DIR=/usr/local/provider
82+
export OPENCODE_PLUGINS_DIR="${OPENCODE_CONFIG_DIR}/plugins"
7983

80-
mkdir -p "${BUN_INSTALL}" "${OPENCODE_CONFIG_DIR}" "${PROVIDER_DIR}"
84+
mkdir -p "${BUN_INSTALL}" "${OPENCODE_CONFIG_DIR}" "${OPENCODE_PLUGINS_DIR}" "${PROVIDER_DIR}"
85+
chmod 0777 "${OPENCODE_CONFIG_DIR}"
8186

8287
bun install -g "opencode-ai@${OPENCODE_VERSION}" || exit 1
8388

@@ -86,31 +91,38 @@ bun install -g "opencode-ai@${OPENCODE_VERSION}" || exit 1
8691
#
8792
pushd /tmp
8893

89-
bun install "github:ophiosdev/azure-foundry-provider" || exit 1
94+
bun install "github:ophiosdev/azure-foundry-provider#v${AZURE_FOUNDRY_PROVIDER_VERSION}" || exit 1
9095
cd node_modules/azure-foundry-provider || exit 1
9196
bun build --outdir=dist src/index.ts || exit 1
9297
mv dist "${PROVIDER_DIR}/azure-foundry-provider"
9398
rm -rf /tmp/*
9499

95100
popd || exit 1
96101

102+
engram_version="${ENGRAM_VERSION#v}"
103+
engram_archive="engram_${engram_version}_linux_amd64.tar.gz"
104+
engram_url="https://github.com/Gentleman-Programming/engram/releases/download/${ENGRAM_VERSION}/${engram_archive}"
105+
curl -fsSL "${engram_url}" | tar -C /usr/local/bin -xvzf - engram
106+
curl -fsSL 'https://raw.githubusercontent.com/Gentleman-Programming/engram/refs/tags/${ENGRAM_VERSION}/plugin/opencode/engram.ts' -o "${OPENCODE_PLUGINS_DIR}/engram.ts"
107+
108+
97109
rm -rf /root/.bun
98110

111+
chown -Rh bun:bun "$(echo ~bun)"
112+
99113
FOE
100114

101-
USER bun
115+
USER bun:bun
102116

103117
RUN mise use -g --silent python@3.12.12 go@1.24 ripgrep uv
104118

105119
# hadolint ignore=DL3045
106120
COPY --chown=bun:bun git-export.py git-export.py
107121

108-
ENV XDG_CONFIG_HOME=/home/bun/.config
109-
110122
RUN <<'FOE'
111123
source /etc/bash.bashrc
112124

113-
skills_dir="${XDG_CONFIG_HOME}/opencode/skills"
125+
skills_dir="${OPENCODE_CONFIG_DIR}/skills"
114126
mkdir -p "${skills_dir}"
115127

116128
skill_name="humanizer"
@@ -126,8 +138,49 @@ RUN <<'FOE'
126138
python git-export.py https://github.com/sickn33/antigravity-awesome-skills/skills/changelog-automation "${skills_dir}/${skill_name}" --force
127139

128140
rm -f git-export.py
141+
142+
cat >"${OPENCODE_CONFIG_DIR}/opencode.json" <<-'EOF'
143+
{
144+
"$schema": "https://opencode.ai/config.json",
145+
"plugin": [
146+
"engram"
147+
],
148+
"mcp": {
149+
"engram": {
150+
"command": [
151+
"engram",
152+
"mcp",
153+
"--tools=agent"
154+
],
155+
"enabled": true,
156+
"type": "local"
157+
},
158+
"sequential-thinking": {
159+
"type": "local",
160+
"command": [
161+
"bun",
162+
"x",
163+
"@modelcontextprotocol/server-sequential-thinking"
164+
]
165+
},
166+
"aleph": {
167+
"type": "local",
168+
"command": [
169+
"aleph",
170+
"--enable-actions",
171+
"--workspace-mode",
172+
"any",
173+
"--tool-docs",
174+
"concise"
175+
]
176+
}
177+
}
178+
}
179+
EOF
180+
129181
FOE
130182

183+
131184
# Set BASH_ENV so non-interactive bash shells (spawned by OpenCode CLI) source /etc/bash.bashrc
132185
# This ensures mise activation and PATH are available in shell commands
133186
ENV BASH_ENV=/etc/bash.bashrc

README.md

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- [Important Environment Variables](#important-environment-variables)
99
- [Verifying Authentication](#verifying-authentication)
1010
- [Azure Foundry Provider](#azure-foundry-provider)
11+
- [Runtime Behavior](#runtime-behavior)
1112
- [Working with OpenCode from the Container](#working-with-opencode-from-the-container)
1213
- [Basic Usage Pattern](#basic-usage-pattern)
1314
- [Volume Mounts Explained](#volume-mounts-explained)
@@ -27,15 +28,16 @@
2728
- [Build and Runtime Issues](#build-and-runtime-issues)
2829

2930
A containerized OpenCode CLI environment with bundled runtime tooling, provider integrations,
30-
and OpenCode skills. This image is designed to give you a ready-to-run `opencode` setup for
31-
local project work while keeping your configuration and working directory mounted from the host.
31+
and reusable OpenCode skills. The image ships with sensible defaults so you can start working in
32+
local projects quickly while still mounting your own workspace, credentials, and persisted user
33+
state from the host.
3234

3335
## Container Architecture
3436

35-
- **OpenCode entrypoint**: The container starts `opencode` directly through `entrypoint.sh`
37+
- **Prepared startup flow**: The entrypoint loads the container shell environment before launching `opencode`
3638
- **Bun-based image**: Uses `oven/bun:latest` as the base image and installs `opencode-ai`
37-
- **Mise-managed tooling**: Activates `mise` for both interactive and non-interactive shells
38-
- **Curated additions**: Bundles Azure Foundry provider support, helper tooling, and reusable skills
39+
- **Consistent shell tooling**: Uses shell bootstrap and `BASH_ENV` so command execution sees the same prepared environment
40+
- **Curated additions**: Bundles Azure Foundry support, memory/context tooling, and reusable skills
3941

4042
## Building the Container Image
4143

@@ -53,11 +55,13 @@ make build
5355

5456
### Build Arguments
5557

56-
Customize the image version and local tag as needed:
58+
Customize the main image component versions and local tag as needed:
5759

5860
```bash
5961
docker build \
6062
--build-arg OPENCODE_VERSION=latest \
63+
--build-arg AZURE_FOUNDRY_PROVIDER_VERSION=0.2.0 \
64+
--build-arg ENGRAM_VERSION=v1.9.1 \
6165
-t opencode-cli:dev .
6266
```
6367

@@ -67,10 +71,15 @@ With `make`:
6771
make build IMAGE=opencode-cli TAG=dev OPENCODE_VERSION=latest
6872
```
6973

74+
The Dockerfile also accepts `AZURE_FOUNDRY_PROVIDER_VERSION` and `ENGRAM_VERSION` if you want to
75+
override the bundled provider or memory-tooling version during a direct `docker build`.
76+
7077
## Authentication Setup
7178

72-
OpenCode configuration is stored under the container user's config directory. For practical use,
73-
mount your host home directory so configuration persists across runs.
79+
The image includes default OpenCode configuration and helper integrations so it works out of the
80+
box, but you should still mount host directories for practical day-to-day use. In most setups,
81+
mounting your host home directory lets OpenCode state, credentials, and memory-related data
82+
persist across runs.
7483

7584
Typical run pattern:
7685

@@ -84,6 +93,7 @@ docker run -it --rm \
8493
This gives the container access to:
8594

8695
- `/home/bun` for OpenCode config and any persisted credentials
96+
- `/home/bun/.local/share/opencode` through the home mount for persisted local OpenCode and memory-related state
8797
- `/work` for the project you want OpenCode to read and modify
8898

8999
### Environment File Option
@@ -113,6 +123,10 @@ Security tips:
113123
The exact variables depend on the provider configuration you use with OpenCode. This image does
114124
not hardcode credentials, so pass provider settings at runtime with `-e` or `--env-file`.
115125

126+
The image also includes default configuration under `/etc/opencode`, so most users only need to
127+
provide environment variables and volume mounts rather than build up the entire runtime setup from
128+
scratch.
129+
116130
Common patterns include:
117131

118132
- OpenAI-compatible endpoints and API keys
@@ -121,8 +135,8 @@ Common patterns include:
121135

122136
### Verifying Authentication
123137

124-
Once your configuration is mounted and any required variables are provided, verify the container
125-
starts correctly:
138+
Once your configuration is mounted and any required variables are provided, verify that the
139+
container starts correctly:
126140

127141
```bash
128142
docker run -it --rm \
@@ -132,7 +146,8 @@ docker run -it --rm \
132146
opencode-cli:dev --help
133147
```
134148

135-
If your setup is correct, OpenCode should start without configuration-related errors.
149+
If your setup is correct, the CLI should start without basic configuration errors. Use a real
150+
provider-backed command when you need to verify credentials end to end.
136151

137152
## Azure Foundry Provider
138153

@@ -143,6 +158,19 @@ This means the container is prepared for Azure Foundry-oriented OpenCode setups
143158
you to compile the provider on first run. Provider credentials and runtime configuration are still
144159
supplied by your OpenCode config and environment variables.
145160

161+
The image also bundles additional helper integrations for memory and large-context workflows, so
162+
common local coding setups can start with a useful default baseline.
163+
164+
## Runtime Behavior
165+
166+
The container does a small amount of runtime preparation before launching OpenCode:
167+
168+
- It loads the shell environment through the entrypoint before starting the CLI
169+
- It uses `BASH_ENV` so non-interactive shell commands inherit the prepared toolchain environment
170+
- It enables OpenCode experimental features by default with `OPENCODE_EXPERIMENTAL=1`
171+
172+
This helps keep CLI sessions and tool-invoked shell commands consistent inside the container.
173+
146174
## Working with OpenCode from the Container
147175

148176
For normal usage, mount both your home directory and the current project directory.
@@ -161,7 +189,7 @@ Replace `[OPENCODE_ARGS]` with the arguments supported by your installed `openco
161189

162190
### Volume Mounts Explained
163191

164-
- `-v $HOME:/home/bun`: Persists OpenCode config and other user-level state
192+
- `-v $HOME:/home/bun`: Persists OpenCode config, credentials, and memory/history data stored under the OpenCode data directory
165193
- `-v ${PWD}:/work`: Mounts your current project into the container working directory
166194
- `--env-file .env`: Supplies provider credentials and runtime settings without exposing them in shell history
167195
- `--rm`: Removes the container after the process exits
@@ -235,6 +263,11 @@ The image currently installs or bundles the following pieces during build:
235263

236264
- `opencode-ai`
237265
- `mise`
266+
- shell bootstrap for interactive and non-interactive command execution
267+
- default OpenCode configuration under `/etc/opencode`
268+
- `engram` for persisted memory-oriented workflows
269+
- `aleph` tooling for large-context local analysis workflows
270+
- local MCP-backed integrations available by default
238271
- `python`
239272
- `go`
240273
- `ripgrep`
@@ -251,7 +284,7 @@ a GitHub repository using a treeless, sparse clone workflow.
251284

252285
This repo publishes container images to GitHub Container Registry from version tags.
253286

254-
- `create-linked-release.yml` polls an upstream repository release stream and mirrors matching tags into this repo
287+
- `create-linked-release.yml` checks the latest matching upstream release on a schedule and creates a local tag when a new one appears
255288
- `build-and-deploy.yml` runs on `v*` tags, validates semver, and publishes the image to `ghcr.io/ophiosdev/opencode-cli`
256289
- Published tags include semver variants, a commit SHA tag, and `latest` when enabled for the default branch
257290

@@ -262,21 +295,23 @@ This repo publishes container images to GitHub Container Registry from version t
262295
- `git-export.py`: Sparse GitHub directory export helper
263296
- `Makefile`: Convenience targets for local image build and cleanup
264297
- `.github/workflows/`: PR validation, release sync, and registry publishing workflows
265-
- `mise.toml`: Local tool definitions for linting and validation utilities
298+
- `.mise.toml`: Local tool definitions for linting and validation utilities
266299

267300
## Development and Validation
268301

269302
The repo uses `pre-commit` for lightweight validation of committed files.
270303

271304
Configured checks include:
272305

306+
- General file hygiene checks from `pre-commit-hooks`
273307
- YAML linting with `yamllint`
274308
- Dockerfile linting with `hadolint`
275309
- Markdown linting with `markdownlint-cli2`
276310
- GitHub Actions validation with `actionlint`
277311
- Spelling checks with `typos`
278312

279-
The pull request workflow also performs a Docker build smoke test when `Dockerfile` changes.
313+
The pull request workflow always runs pre-commit checks and also performs a Docker build smoke
314+
test when `Dockerfile` changes.
280315

281316
## Troubleshooting
282317

@@ -285,6 +320,7 @@ The pull request workflow also performs a Docker build smoke test when `Dockerfi
285320
- Repeated setup prompts: ensure `-v $HOME:/home/bun` is present so config persists
286321
- Missing credentials: confirm required provider variables are passed with `-e` or `--env-file`
287322
- Startup config failures: run `opencode-cli:dev --help` first to confirm the base container starts cleanly
323+
- Memory/history not persisting: confirm your `/home/bun` mount is present so OpenCode state survives container recreation
288324

289325
### File Access Issues
290326

0 commit comments

Comments
 (0)