update source code (3 files)
This commit is contained in:
79
docker/opencode/Dockerfile
Normal file
79
docker/opencode/Dockerfile
Normal file
@@ -0,0 +1,79 @@
|
||||
# GrowQR OpenCode runtime image
|
||||
#
|
||||
# This wraps the upstream OpenCode image with GrowQR-owned prompt modules,
|
||||
# sub-agent definitions, workspace template files, and runtime bootstrap.
|
||||
#
|
||||
# Build from growqr-backend/:
|
||||
# docker build -f docker/opencode/Dockerfile -t growqr/opencode:dev .
|
||||
#
|
||||
# Release flow:
|
||||
# docker build -f docker/opencode/Dockerfile \
|
||||
# --build-arg GROWQR_IMAGE_VERSION=2026.06.01-1 \
|
||||
# -t ghcr.io/<org>/growqr-opencode:2026.06.01-1 \
|
||||
# -t ghcr.io/<org>/growqr-opencode:latest .
|
||||
|
||||
ARG OPENCODE_BASE_IMAGE=ghcr.io/anomalyco/opencode:latest
|
||||
FROM ${OPENCODE_BASE_IMAGE}
|
||||
|
||||
ARG GROWQR_IMAGE_VERSION=dev
|
||||
ARG GROWQR_PROMPT_VERSION=dev
|
||||
ARG GROWQR_MIGRATION_VERSION=1
|
||||
|
||||
ENV GROWQR_IMAGE_VERSION=${GROWQR_IMAGE_VERSION}
|
||||
ENV GROWQR_PROMPT_VERSION=${GROWQR_PROMPT_VERSION}
|
||||
ENV GROWQR_MIGRATION_VERSION=${GROWQR_MIGRATION_VERSION}
|
||||
ENV GROWQR_HOME=/opt/growqr
|
||||
ENV OPENCODE_WORKSPACE=/workspace
|
||||
|
||||
USER root
|
||||
|
||||
# Ensure the runtime has the basics needed for Git-backed memory. The upstream
|
||||
# image may already include these, but this keeps our image contract explicit.
|
||||
RUN if command -v apk >/dev/null 2>&1; then \
|
||||
apk add --no-cache git openssh-client ca-certificates bash curl jq; \
|
||||
elif command -v apt-get >/dev/null 2>&1; then \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
git openssh-client ca-certificates bash curl jq && \
|
||||
rm -rf /var/lib/apt/lists/*; \
|
||||
else \
|
||||
echo "Unsupported base image package manager" >&2; exit 1; \
|
||||
fi
|
||||
|
||||
RUN mkdir -p \
|
||||
/workspace \
|
||||
/root/.config/opencode \
|
||||
/root/.local/share/opencode \
|
||||
/opt/growqr/agents \
|
||||
/opt/growqr/prompts \
|
||||
/opt/growqr/workspace-template/memory \
|
||||
/opt/growqr/workspace-template/conversations \
|
||||
/opt/growqr/workspace-template/state \
|
||||
/opt/growqr/workspace-template/artifacts \
|
||||
/opt/growqr/workspace-template/workflows \
|
||||
/opt/growqr/workspace-template/logs \
|
||||
/opt/growqr/workspace-template/config \
|
||||
/opt/growqr/workspace-template/metadata
|
||||
|
||||
# GrowQR sub-agent prompt modules. These are image-versioned: update the files,
|
||||
# rebuild/push a new image, then set OPENCODE_IMAGE + OPENCODE_IMAGE_VERSION in
|
||||
# the backend rollout.
|
||||
COPY agents/ /opt/growqr/agents/
|
||||
COPY prompts/ /opt/growqr/prompts/
|
||||
COPY docker/opencode/growqr.json /root/.config/opencode/growqr.json
|
||||
COPY docker/opencode/entrypoint.sh /usr/local/bin/growqr-opencode-entrypoint
|
||||
|
||||
# Starter Git workspace. The backend will normally create the real central
|
||||
# Gitea repo and clone it into /workspace after the server starts. This template
|
||||
# makes fresh/standalone containers still look like a GrowQR memory repo and
|
||||
# gives OpenCode immediate local context before clone/sync completes.
|
||||
COPY docker/opencode/workspace-template/ /opt/growqr/workspace-template/
|
||||
RUN chmod +x /usr/local/bin/growqr-opencode-entrypoint && \
|
||||
mkdir -p /opt/growqr/workspace-template/metadata && \
|
||||
printf '%s\n' \
|
||||
"{\"imageVersion\":\"${GROWQR_IMAGE_VERSION}\",\"promptVersion\":\"${GROWQR_PROMPT_VERSION}\",\"migrationVersion\":\"${GROWQR_MIGRATION_VERSION}\"}" \
|
||||
> /opt/growqr/workspace-template/metadata/image.json
|
||||
|
||||
WORKDIR /workspace
|
||||
EXPOSE 4096
|
||||
ENTRYPOINT ["growqr-opencode-entrypoint"]
|
||||
CMD ["opencode", "serve", "--port", "4096", "--hostname", "0.0.0.0"]
|
||||
63
docker/opencode/README.md
Normal file
63
docker/opencode/README.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# GrowQR OpenCode Runtime Image
|
||||
|
||||
This folder defines the custom per-user OpenCode image used by the Rivet user actor lifecycle.
|
||||
|
||||
## Why this exists
|
||||
|
||||
The upstream image (`ghcr.io/anomalyco/opencode:latest`) is only the base runtime. GrowQR needs an owned image that bakes in:
|
||||
|
||||
- GrowQR sub-agent markdown modules from `agents/`
|
||||
- GrowQR system prompts from `prompts/`
|
||||
- global OpenCode config under `/root/.config/opencode`
|
||||
- a Git-backed workspace template under `/opt/growqr/workspace-template`
|
||||
- runtime metadata for image/prompt/migration rollout checks
|
||||
|
||||
## Local build
|
||||
|
||||
From `growqr-backend/`:
|
||||
|
||||
```bash
|
||||
docker build -f docker/opencode/Dockerfile -t growqr/opencode:dev .
|
||||
```
|
||||
|
||||
Then run the backend with:
|
||||
|
||||
```bash
|
||||
OPENCODE_IMAGE=growqr/opencode:dev OPENCODE_IMAGE_VERSION=dev PROMPT_VERSION=dev docker compose up -d --build backend
|
||||
```
|
||||
|
||||
For the current compose setup, the backend talks to the host Docker socket, so local images built on the host are available to per-user containers.
|
||||
|
||||
## Release build
|
||||
|
||||
```bash
|
||||
VERSION=2026.06.01-1
|
||||
docker build -f docker/opencode/Dockerfile \
|
||||
--build-arg GROWQR_IMAGE_VERSION=$VERSION \
|
||||
--build-arg GROWQR_PROMPT_VERSION=$VERSION \
|
||||
-t ghcr.io/<org>/growqr-opencode:$VERSION \
|
||||
-t ghcr.io/<org>/growqr-opencode:latest .
|
||||
docker push ghcr.io/<org>/growqr-opencode:$VERSION
|
||||
docker push ghcr.io/<org>/growqr-opencode:latest
|
||||
```
|
||||
|
||||
Then update backend env:
|
||||
|
||||
```bash
|
||||
OPENCODE_IMAGE=ghcr.io/<org>/growqr-opencode:$VERSION
|
||||
OPENCODE_IMAGE_VERSION=$VERSION
|
||||
PROMPT_VERSION=$VERSION
|
||||
```
|
||||
|
||||
## Runtime behavior
|
||||
|
||||
The backend/Rivet actor still owns lifecycle:
|
||||
|
||||
1. provision central Gitea repo for the user
|
||||
2. start one OpenCode container from this image
|
||||
3. mount host workspace at `/workspace`
|
||||
4. wait for OpenCode readiness
|
||||
5. clone/pull the user's Gitea repo into `/workspace`
|
||||
6. sync important runtime outputs back to Git
|
||||
|
||||
The image only provides the runtime and templates; user data remains in the user's central Gitea repo.
|
||||
52
docker/opencode/entrypoint.sh
Normal file
52
docker/opencode/entrypoint.sh
Normal file
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
WORKSPACE="${OPENCODE_WORKSPACE:-/workspace}"
|
||||
GROWQR_HOME="${GROWQR_HOME:-/opt/growqr}"
|
||||
TEMPLATE="$GROWQR_HOME/workspace-template"
|
||||
|
||||
mkdir -p "$WORKSPACE" /root/.config/opencode /root/.local/share/opencode
|
||||
|
||||
# Make sub-agents discoverable from common OpenCode/global locations. We keep
|
||||
# the canonical copy in /opt/growqr and symlink/copy to config paths so future
|
||||
# OpenCode versions can pick up either convention.
|
||||
ln -sfn "$GROWQR_HOME/agents" /root/.config/opencode/agents
|
||||
ln -sfn "$GROWQR_HOME/prompts" /root/.config/opencode/prompts
|
||||
ln -sfn "$GROWQR_HOME/agents" /root/.local/share/opencode/agents
|
||||
ln -sfn "$GROWQR_HOME/prompts" /root/.local/share/opencode/prompts
|
||||
|
||||
# Seed an empty mounted workspace with the GrowQR Git-backed memory shape. The
|
||||
# backend later clones the user's central Gitea repo over this workspace when it
|
||||
# provisions the user stack. This only runs for truly empty workspaces.
|
||||
if [ -z "$(find "$WORKSPACE" -mindepth 1 -maxdepth 1 2>/dev/null | head -n 1)" ]; then
|
||||
cp -a "$TEMPLATE"/. "$WORKSPACE"/
|
||||
cat > "$WORKSPACE/README.md" <<EOF
|
||||
# GrowQR User Workspace
|
||||
|
||||
This workspace is controlled by GrowQR's Rivet user actor and backed by the
|
||||
user's central Gitea repository. OpenCode runs here with GrowQR sub-agents
|
||||
available globally from:
|
||||
|
||||
- /opt/growqr/agents
|
||||
- /opt/growqr/prompts
|
||||
- /root/.config/opencode/agents
|
||||
|
||||
EOF
|
||||
git -C "$WORKSPACE" init -b main >/dev/null 2>&1 || true
|
||||
git -C "$WORKSPACE" config user.email "growqr@local" || true
|
||||
git -C "$WORKSPACE" config user.name "GrowQR" || true
|
||||
git -C "$WORKSPACE" add -A >/dev/null 2>&1 || true
|
||||
git -C "$WORKSPACE" commit -m "init: growqr workspace template" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
cat > "$WORKSPACE/.growqr-runtime.json" <<EOF
|
||||
{
|
||||
"imageVersion": "${GROWQR_IMAGE_VERSION:-dev}",
|
||||
"promptVersion": "${GROWQR_PROMPT_VERSION:-dev}",
|
||||
"migrationVersion": "${GROWQR_MIGRATION_VERSION:-1}",
|
||||
"agentsDir": "$GROWQR_HOME/agents",
|
||||
"promptsDir": "$GROWQR_HOME/prompts"
|
||||
}
|
||||
EOF
|
||||
|
||||
exec "$@"
|
||||
10
docker/opencode/growqr.json
Normal file
10
docker/opencode/growqr.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"growqr": {
|
||||
"name": "GrowQR OpenCode Runtime",
|
||||
"agentsDir": "/opt/growqr/agents",
|
||||
"promptsDir": "/opt/growqr/prompts",
|
||||
"workspace": "/workspace",
|
||||
"memoryRepo": "git-backed",
|
||||
"notes": "This file is baked into the custom GrowQR OpenCode image. Update agents/prompts and rebuild the image to release sub-agent changes."
|
||||
}
|
||||
}
|
||||
3
docker/opencode/workspace-template/artifacts/README.md
Normal file
3
docker/opencode/workspace-template/artifacts/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Artifacts
|
||||
|
||||
Generated resumes, interview notes, reports, scorecards, and other deliverables.
|
||||
3
docker/opencode/workspace-template/config/README.md
Normal file
3
docker/opencode/workspace-template/config/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Config
|
||||
|
||||
User-specific GrowQR/OpenCode runtime configuration.
|
||||
@@ -0,0 +1,3 @@
|
||||
# Conversations
|
||||
|
||||
Conversation exports and assistant summaries.
|
||||
3
docker/opencode/workspace-template/logs/README.md
Normal file
3
docker/opencode/workspace-template/logs/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Logs
|
||||
|
||||
Runtime logs or summaries that are safe to persist to the user's repo.
|
||||
3
docker/opencode/workspace-template/memory/README.md
Normal file
3
docker/opencode/workspace-template/memory/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Memory
|
||||
|
||||
Durable user career memory. The GrowQR actor and OpenCode runtime should write stable facts, preferences, decisions, and summaries here.
|
||||
3
docker/opencode/workspace-template/state/README.md
Normal file
3
docker/opencode/workspace-template/state/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# State
|
||||
|
||||
Small serialized workflow/runtime state that should be visible in Git.
|
||||
3
docker/opencode/workspace-template/workflows/README.md
Normal file
3
docker/opencode/workspace-template/workflows/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Workflows
|
||||
|
||||
Workflow run notes, plans, approvals, and outputs.
|
||||
Reference in New Issue
Block a user