Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions .github/workflows/image-size.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: image-size

# Builds the aidc Dockerfile template with a representative toolchain set and
# reports/asserts the resulting image size so regressions are caught before
# merge. The budget is a soft gate (informational) — the comment is posted on
# PRs so maintainers can see the number without blocking development.

on:
pull_request:
branches: [main]
push:
branches: [main]

permissions:
contents: read
pull-requests: write

concurrency:
group: image-size-${{ github.ref }}
cancel-in-progress: true

jobs:
size:
name: image size (go,node,python)
runs-on: ubuntu-latest
timeout-minutes: 60

steps:
- uses: actions/checkout@v6

- name: Scaffold representative project
run: |
set -euo pipefail
mkdir -p work
cp templates/devcontainer/Dockerfile.tmpl work/Dockerfile
cat > work/project-setup.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
:
EOF
# Trigger the go/node/python toolchain arms.
touch work/go.mod
printf '{"name":"x","version":"1.0.0"}\n' > work/package.json
printf 'uv\n' > work/uv.lock

- name: Build image
run: |
set -euo pipefail
docker build \
--build-arg AIDC_TOOLCHAINS=go,node,python \
--build-arg AIDC_SECURITY_TOOLS= \
-t aidc-size-probe work
docker images aidc-size-probe --format '{{.Size}}' > /tmp/image-size.txt
SIZE=$(docker images aidc-size-probe --format '{{.Size}}')
echo "IMAGE_SIZE=$SIZE" >> "$GITHUB_ENV"
echo "Built image size: $SIZE"

- name: Report size on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const size = process.env.IMAGE_SIZE;
const msg = `**aidc image size** (toolchains: go,node,python): \`${size}\`\n\n` +
`Previous reference: ~4–6 GB. Budget is informational for now — ` +
`tighten after the size-reduction PRs land.`;
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: msg,
});

- name: Budget assertion (soft)
run: |
set -euo pipefail
SIZE=$(docker images aidc-size-probe --format '{{.Size}}')
# 6 GB ceiling as a sanity gate; tighten after optimizations land.
BYTES=$(echo "$SIZE" | awk '{
if ($0 ~ /GB$/) print $0 * 1024 * 1024 * 1024;
else if ($0 ~ /MB$/) print $0 * 1024 * 1024;
else print $0
}')
echo "size bytes: $BYTES"
MAX=$((6 * 1024 * 1024 * 1024))
if [ "$BYTES" -gt "$MAX" ]; then
echo "::warning::image size $SIZE exceeds the 6 GB soft budget"
else
echo "image size $SIZE within budget"
fi
12 changes: 10 additions & 2 deletions lib/aidc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -497,8 +497,11 @@ aidc::cmd_status_global() {
fi

# One-shot disk and stats lookups so we don't fork docker per container.
local size_map stats_map running_ids
local size_map stats_map running_ids image_map
size_map="$(docker container ls --all --size --format '{{.ID}}|{{.Size}}' 2>/dev/null)"
# Image sizes by image ID, so we can show the on-disk image footprint per
# project without a docker fork per container.
image_map="$(docker image ls --no-trunc --format '{{.ID}}|{{.Size}}' 2>/dev/null)"
running_ids="$(printf '%s\n' "$rows" | awk -F'|' '$3=="running" {printf "%s ", $1}')"
stats_map=''
if [[ -n "$running_ids" ]]; then
Expand All @@ -515,8 +518,11 @@ aidc::cmd_status_global() {
local workspace="${working_dir%/.devcontainer*}"
[[ -z "$workspace" ]] && workspace='(unknown)'

local size
local size image_size
size="$(printf '%s\n' "$size_map" | awk -F'|' -v id="$id" 'index($1,id)==1 {print $2; exit}')"
local cimage
cimage="$(docker inspect --format '{{.Image}}' "$id" 2>/dev/null || true)"
image_size="$(printf '%s\n' "$image_map" | awk -F'|' -v img="$cimage" 'index($1,img)==1 {print $2; exit}')"

if [[ "$state" == "running" ]]; then
running=$((running + 1))
Expand All @@ -535,6 +541,7 @@ aidc::cmd_status_global() {
"$C_LBL" "$C_RST" "${cpu:-?}" \
"$C_LBL" "$C_RST" "${mem:-?}" \
"$C_LBL" "$C_RST" "${pids:-?}"
[[ -n "$image_size" ]] && printf ' %simage%s %s\n' "$C_LBL" "$C_RST" "$image_size"
[[ -n "$started" ]] && printf ' %ssince%s %s\n' "$C_LBL" "$C_RST" "$started"
else
stopped=$((stopped + 1))
Expand All @@ -545,6 +552,7 @@ aidc::cmd_status_global() {
printf ' %s○ %s%s %s\n' "$C_WARN" "$state" "$C_RST" "$slug"
printf ' %s%s%s\n' "$C_DIM" "$workspace" "$C_RST"
printf ' %sdisk%s %s\n' "$C_LBL" "$C_RST" "${size:-?}"
[[ -n "$image_size" ]] && printf ' %simage%s %s\n' "$C_LBL" "$C_RST" "$image_size"
[[ -n "$exited" ]] && printf ' %sexited%s %s\n' "$C_LBL" "$C_RST" "$exited"
fi
printf '\n'
Expand Down