Skip to content

Docker image GitHub release fallback#197

Draft
thunderock wants to merge 21 commits into
johannesjo:mainfrom
thunderock:docker-image-github-release-fallback
Draft

Docker image GitHub release fallback#197
thunderock wants to merge 21 commits into
johannesjo:mainfrom
thunderock:docker-image-github-release-fallback

Conversation

@thunderock

Copy link
Copy Markdown

Description

Describe what this change achieves

Issues Resolved

List any existing issues this PR resolves

Check List

  • New functionality includes testing.
  • New functionality has been documented in the README if applicable.

…d strings

- Identifiers: name/productName/appId (com.forge.app), StartupWMClass
- Functional paths: .forge/, ~/.forge/agent-auth/, forge-* temp prefixes
- MCP server key parallel-code -> forge; env vars PARALLEL_CODE_* -> FORGE_*
- Code symbols ParallelCode* -> Forge*; updated test fixtures + a stale length assertion
- Technical word 'parallel' (in parallel/parallelization) left untouched
- package.json author -> thunderock; all repo links -> github.com/thunderock/forge
- PRIVACY contact reworded; email -> findashutoshtiwari@gmail.com
- README License section credits the Parallel Code (MIT) origin
- --no-verify: author-only package.json edit; lockfile verified in sync (hook checks co-presence, not content)
Removes the 10s post-launch checkForUpdates() timer (and its cleanup) so a
local/personal build makes no automatic update network call. Manual
'Check for updates' (checkForUpdates) and the rest of the updater stay intact.
- Replace the parallel '|| ][' glyph with an ember-orange 4-point spark mark
  across icon.svg, icon-squared/rounded.svg, src/assets/logo.svg
- Rebuild logo-text(.squared).svg wordmarks: spark + 'Forge'
- Retheme default look accent family cyan -> ember in styles.css
  (--accent/--accent-hover/--link/--border-focus), monaco theme, remote UI
- Regenerate icon.png/icon.icns/icon.ico/128x128(@2x).png from the new mark
Drop the cert-import + notarization steps from the mac job and build with
CSC_IDENTITY_AUTO_DISCOVERY=false and -c.mac.notarize=false, so a v* tag push
produces a draft release with unsigned .dmg + Linux .AppImage/.deb using only
GITHUB_TOKEN. Restore-signing instructions left as a comment.
docs(brand): remove upstream Parallel Code YouTube intro link from RE…
Rebuild forge-agent:latest as a multi-stage Dockerfile: parallel rust/go/tools builder stages + the existing agent base. Adds uv+Python 3.11, Rust 1.93, Go 1.24.4, AWS CLI v2, lazygit/delta/bat/starship, ruff/black/isort/mypy, tmux/htop/direnv, and curated secret-free dotfiles + vim-gitgutter. NOTE: not built locally (Colima VM had no egress); verify build in CI / on a networked machine before merge.
Point the default agent image at thunderockforge/forge-agent:latest so Docker-mode tasks pull it from Hub instead of building locally (DEFAULT_DOCKER_IMAGE, DOCKER_DEFAULT_IMAGE, and the store/persistence/ui defaults). Add .github/workflows/docker-image.yml: PRs touching docker/** build (amd64) to verify; push to main builds multi-arch on native runners and publishes :latest. Requires DOCKERHUB_USERNAME + DOCKERHUB_TOKEN secrets.
Slim the shipped agent image and bake the gsd (get-shit-done) workflow
layer in so Docker-mode agents have it available.

- Remove starship, tmux, and the `set -o emacs` readline mode
- Bake gsd into the /home/agent skeleton (~/.claude via get-shit-done-cc
  --global + secret-free ~/.gsd/defaults.json)
- Seed gsd into each task's per-agent $HOME at container start (pty.ts);
  cp -an is no-clobber so a shared-auth .claude bind mount keeps creds
- Antigravity (agy) intentionally kept

Local image build is blocked by the Colima VM egress; the gsd install
step is verified by the CI `verify` job.
feat(docker): richer multi-stage agent image
Docker-mode tasks relied on `docker run`'s implicit pull, so a transient Docker Hub registry timeout hard-failed the task with a cryptic daemon error. Add a pre-pull step in front of `docker run`:

- fast path: a cached image spawns synchronously (cached per session)
- missing image: `docker pull` with 3 retries + backoff, streaming progress
- fall back to any locally cached copy before giving up
- friendly error + clean exit instead of a raw daemon dump
- cancellation-safe on kill / renderer reattach mid-pull

Project images (forge-project:*) and non-Docker tasks are unchanged.
feat(docker): resilient agent image pre-pull with retry + fallback
The tools builder resolved versions via unauthenticated curl to api.github.com/.../releases/latest, whose 60-req/hr/IP limit intermittently 403'd CI runners (arm64 build was failing). Pin both versions and download the release assets directly from github.com/.../releases/download (not rate-limited), plus curl --retry for transient blips.

lazygit 0.62.2, delta 0.19.2 — bump via the ARG defaults.
fix(docker): pin lazygit + delta, drop rate-limited GitHub API calls
…s unreachable

The agent-image pre-pull runs inside the Docker daemon, so it fails for ANY registry (Docker Hub, GHCR) when the daemon lives in a VM with no internet egress — e.g. a Colima/Lima VM whose virtual network a corporate VPN doesn't route. Retrying or switching registries can't help. Add a host-side fallback: the host (which does have network) downloads the image tarball from the GitHub release and `docker load`s it into the daemon over the socket, which needs no VM egress.

- electron/ipc/docker-pull.ts: acquireAgentImage() fallback chain (cached -> docker pull -> GitHub-release download + docker load -> local build) plus downloadAndLoadReleaseImage() with sha256 verification and pinned->latest URL fallback
- electron/ipc/pty.ts: wire the chain in for the default image; replace the terse pull error with a VM-egress diagnostic
- .github/workflows/release.yml: build the agent image on native runners and attach per-arch forge-agent-<arch>.tar.gz + .sha256 to each release
- docker-pull.test.ts: cover chain ordering, download, checksum mismatch, and 404->latest fallback
@thunderock
thunderock marked this pull request as draft July 6, 2026 19:34
@johannesjo

Copy link
Copy Markdown
Owner

Thanks for this @thunderock — there's genuinely nice engineering in here, but as it stands I can't merge it. Let me explain clearly so we can salvage the good part.

The blocker: this PR is a rebranded fork, not a feature

The branch carries a wholesale rename of the project from Parallel Code → Forge and reassigns its identity. Across the ~80 files, these stand out:

  • .github/FUNDING.yml — sponsorship redirected johannesjothunderock
  • package.jsonauthor, productName (Forge), appId (com.forge.app), and the GitHub publish target all changed to thunderock/forge
  • .github/workflows/release.ymlremoves macOS code signing + notarization (cert import, notarization API key, and cleanup steps deleted; switches to CSC_IDENTITY_AUTO_DISCOVERY=false + -c.mac.notarize=false). Official releases would become unsigned and get blocked by Gatekeeper.
  • electron/ipc/updater.ts — disables the post-launch auto-update check
  • .github/workflows/docker-image.yml — pushes to docker.io/thunderockforge/forge-agent using DOCKERHUB_* secrets this repo doesn't have

There's also a silent breaking change for existing users: renaming productName/appId moves the Electron userData directory (~/.config/Parallel Code~/.config/Forge, and the macOS equivalent), so everyone's tasks, settings, themes, and keybindings would disappear with no migration. Same for the on-disk .parallel-code/.forge/, the MCP server key parallel-codeforge, and PARALLEL_CODE_MCP_TOKENFORGE_MCP_TOKEN.

I'm assuming the branch was opened by mistake — it looks like your fork's main rather than an isolated feature branch.

The good part I'd love to keep

The Docker image-acquisition fallback in electron/ipc/docker-pull.ts is well done — dependency-injected, fully abortable (renderer reload / kill / kill-all all cancel in-flight pulls cleanly), retry + backoff, SHA-256 verified, with a solid ~300-line test suite. The layered chain (cached → docker pull → GitHub-release tarball + docker load → local build) genuinely solves the egress-less-VM problem (Colima/Lima under a VPN, where the daemon can't reach a registry but the host can). The pty.ts refactor that wraps the spawn body in a launch() closure so acquisition can run first is clean too.

What I'd ask

Could you close this and open a branch cut fresh from main containing only the Docker feature:

  • electron/ipc/docker-pull.ts + its test
  • the pty.ts image-acquisition wiring
  • the release.yml agent-image tarball-upload job — without the signing/notarization removal
  • image name, owner/repo, and any registry namespace pointing back at parallel-code / johannesjo

…and drop every Parallel Code → Forge / thunderock identity change (FUNDING, package.json, updater, rename churn, icons/SVGs, test fixtures).

Two smaller notes for that version:

  • docker-pull.ts — the checksum is only enforced when the .sha256 asset is present; a missing/404 checksum loads the tarball unverified. Fine as a deliberate degrade, but worth a comment (or fail-closed for the default image).
  • dockerImagePresentSync — runs execFileSync with a 4s timeout on the synchronous spawn fast-path, i.e. on the Electron main thread; a hung Docker daemon would freeze the UI for up to 4s at launch. Consider keeping that path async.

Happy to review the moment it's a clean feature-only diff. Thanks again — the fallback design itself is exactly the kind of resilience I want.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants