Last active
February 5, 2026 18:49
-
-
Save legionus/3e3e566df6bb1af9ee7da7bca9f68d00 to your computer and use it in GitHub Desktop.
The project allows you to manage isolated containers with AI agents.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # SPDX-License-Identifier: GPL-2.0-or-later | |
| # Copyright (C) 2026 Alexey Gladkov <gladkov.alexey@gmail.com> | |
| CURNAME = devkit | |
| CURFILE = $(lastword $(MAKEFILE_LIST)) | |
| V = $(VERBOSE) | |
| Q = $(if $(V),,@) | |
| define require-utility | |
| $(eval $(1) := $(shell command -v $(2) 2>/dev/null)) | |
| $(if $($(1)),,$(error Required utility '$(2)' not found)) | |
| endef | |
| $(call require-utility,GIT,git) | |
| $(call require-utility,PODMAN,podman) | |
| $(call require-utility,CURL,curl) | |
| GITPROJDIR = $(shell $(GIT) rev-parse --show-toplevel 2>/dev/null) | |
| PROJNAME = $(notdir $(GITPROJDIR)) | |
| $(if $(PROJNAME),,$(error Unable to locate the git repository.)) | |
| DEF_AGENT = copilot | |
| DEF_DEVNAME = $(PROJNAME) | |
| AGENT = $(shell $(GIT) config get devkit.agent || echo $(DEF_AGENT)) | |
| DEVNAME = $(shell $(GIT) config get devkit.name || echo $(DEF_DEVNAME)) | |
| DEVPKGS = $(shell $(GIT) config get --all devkit.packages) | |
| SHAHASH = $(shell echo $(AGENT) $(sort $(DEVPKGS)) | sha256sum | cut -f1 -d\ ) | |
| AGENT.copilot.HOME = https://github.com/github/copilot-cli/releases/latest | |
| AGENT.copilot.URL = $(AGENT.copilot.HOME)/download/copilot-linux-x64.tar.gz | |
| AGENT.copilot.BIN = copilot | |
| AGENT.copilot.VOLUMES = $(HOME)/.copilot:/root/.copilot:rw | |
| AGENT.copilot.BASE = docker.io/library/ubuntu:latest | |
| AGENT.codex.HOME = https://github.com/openai/codex/releases/latest | |
| AGENT.codex.URL = $(AGENT.codex.HOME)/download/codex-x86_64-unknown-linux-gnu.tar.gz | |
| AGENT.codex.BIN = codex-x86_64-unknown-linux-gnu | |
| AGENT.codex.VOLUMES = $(HOME)/.codex:/root/.codex:rw | |
| AGENT.codex.BASE = docker.io/library/ubuntu:latest | |
| AGENT.opencode.HOME = https://github.com/anomalyco/opencode/releases/latest | |
| AGENT.opencode.URL = $(AGENT.opencode.HOME)/download/opencode-linux-x64.tar.gz | |
| AGENT.opencode.BIN = opencode | |
| AGENT.opencode.VOLUMES = $(HOME)/.config/opencode:/root/.config/opencode:rw | |
| AGENT.opencode.BASE = docker.io/library/ubuntu:latest | |
| AGENT.gemini.HOME = https://github.com/google-gemini/gemini-cli/releases/latest | |
| AGENT.gemini.URL = | |
| AGENT.gemini.BIN = gemini | |
| AGENT.gemini.VOLUMES = $(HOME)/.gemini:/root/.gemini:rw | |
| AGENT.gemini.VERSION = $(shell $(CURL) --silent --head --no-location "$(AGENT.gemini.HOME)" | sed -n 's/^location: http.*\/tag\/v//p') | |
| AGENT.gemini.BASE = us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:$(AGENT.gemini.VERSION) | |
| IMG_WORKDIR = /srv/$(PROJNAME) | |
| IMG_VOLUMES = $(GITPROJDIR):$(IMG_WORKDIR) $(AGENT.$(AGENT).VOLUMES) | |
| # Rules | |
| .PHONY: _check-image _create-image help init clean check upgrade list run | |
| .ONESHELL: | |
| help: | |
| @echo "" | |
| echo "Usage: make -f $(CURFILE) [ help$(foreach x,init clean check upgrade list run, | $(x)) ]" | |
| echo "" | |
| echo "The project allows you to manage isolated containers with AI agents." | |
| echo "" | |
| echo "Commands:" | |
| echo " init creates the initial configuration in git-config." | |
| echo " list shows all devkit known images." | |
| echo " check shows current and available agent versions." | |
| echo " upgrade upgrades podman image for current devkit." | |
| echo " run starts devkit container." | |
| echo " clean deletes all images for the current devkit." | |
| echo " clean-all deletes all devkit images." | |
| echo " help display this help and exit." | |
| echo "" | |
| echo "Report bugs to authors." | |
| echo "" | |
| init: | |
| $(Q)if ! $(GIT) config get devkit.name >/dev/null 2>&1; then | |
| $(GIT) config set devkit.name "$(DEVNAME)"; | |
| $(GIT) config set devkit.agent "$(AGENT)"; | |
| $(GIT) config set devkit.packages "bash"; | |
| else | |
| echo "Discovered the existing configuration and cowardly refuse to break it." >&2; | |
| fi | |
| get-image-id = $(shell $(PODMAN) image list --filter label=local.devkit.hash=$(SHAHASH) --format '{{.Id}}') | |
| get-avail-version = $(shell $(CURL) --silent --head --no-location "$(AGENT.$(AGENT).HOME)" | sed -n 's/^location: .*\/tag\///p') | |
| _create-image: | |
| $(Q)[ -n "$(get-image-id)" ] || printf '%s\n' \ | |
| "FROM $(AGENT.$(AGENT).BASE)" \ | |
| "USER root" \ | |
| "RUN apt-get update" \ | |
| "RUN apt-get -y install $(sort ca-certificates bash curl tar $(DEVPKGS))" \ | |
| "RUN apt-get -y clean" \ | |
| "RUN ln -s -- '/bin/bash' '/usr/bin/agent'" \ | |
| "RUN [ '$(words $(AGENT.$(AGENT).URL))' -eq 0 ] || { curl -fsSL '$(AGENT.$(AGENT).URL)' | tar -C /usr/local/bin -zxf-; }" \ | |
| "RUN [ '$(words $(AGENT.$(AGENT).BIN))' -eq 0 ] || { ln -sf -- \"\`command -v $(AGENT.$(AGENT).BIN)\`\" '/usr/bin/agent'; }" \ | |
| "LABEL local.devkit.name=$(DEVNAME)" \ | |
| "LABEL local.devkit.hash=$(SHAHASH)" \ | |
| "LABEL local.devkit.agent=$(AGENT)" \ | |
| "LABEL local.devkit.agent.version=$(get-avail-version)" \ | |
| "CMD /usr/bin/agent" | | |
| $(PODMAN) image build --squash --force-rm -t "localhost/$(CURNAME)/$(DEVNAME):latest" -f-; | |
| _check-image: | |
| $(Q)[ -n "$(get-image-id)" ] || $(MAKE) -f "$(CURFILE)" _create-image | |
| run: _check-image | |
| $(Q)$(PODMAN) container run $(addprefix -v ,$(IMG_VOLUMES)) --workdir="$(IMG_WORKDIR)" --rm --tty --interactive -- "$(get-image-id)" $(CMD) || \ | |
| echo "container exit status $$?" | |
| check: | |
| $(Q)image_id="$(get-image-id)"; | |
| avail_ver="$(get-avail-version)"; | |
| image_ver="`[ -z "$$image_id" ] || $(PODMAN) image inspect "$$image_id" --format '{{index .Labels "local.devkit.agent.version"}}'`"; | |
| echo "The $(AGENT) information:"; | |
| echo " - release home page: $(AGENT.$(AGENT).HOME)"; | |
| echo " - available version: $${avail_ver:-*unavailable*}"; | |
| echo " - current version: $${image_ver:-*unknown*}"; | |
| clean-all: | |
| $(Q)$(PODMAN) image list --filter label=local.devkit.name --format '{{.Id}}' | xargs -r $(PODMAN) image rm | |
| clean: | |
| $(Q)$(PODMAN) image list --filter label=local.devkit.name=$(DEVNAME) --format '{{.Id}}' | xargs -r $(PODMAN) image rm | |
| upgrade: clean | |
| $(Q)$(MAKE) -f "$(CURFILE)" _create-image | |
| list: | |
| $(Q)$(PODMAN) image list --filter label=local.devkit.name |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment