Skip to content
oldsjPublic

About

A single conversation to manage all of your AI sessions - that keeps working while you're away

Resources

Contributing

Stars

7 stars

Watchers

1 watching

Forks

Latest commit

 

History

283 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GitHub automation

The workflow files are the source of truth for triggers and job settings. Image publication is separate from deployment; these workflows do not deploy workloads. Changes under .github/** remain owner-protected.

Pull request and main checks

CI runs on every pull request targeting main and every push to main, without path filters. Jobs check the exact PR head or push commit:

  • command-deadlines: command deadline and process-cleanup tests via make test-timeouts (5 minutes).
  • lint: Trunk checks with explicit base/head SHAs and check annotations (5 minutes).

Stack-specific checks run in their own workflows, filtered by path:

  • Go: golangci-lint, go test -race (sharded across two jobs: internal/tasks, internal/sessions and internal/workspaces in one, everything else in the other), generated-code drift, the MCP tool contract (make check-mcp-tools), and the prod image build from server/Dockerfile. The MCP contract is generated by go generate ./internal/mcpserver and checked by make check-mcp-tools. Go nightly reruns the full suite with go test -race -count=1 ./... once a day as a backstop against a stale cached result, since the PR jobs above cache Go build and module state across runs.
  • Web: tsc, ESLint, Vitest, the Vite build, design checks, API and theme drift, the static server test, and the web/Dockerfile build.
  • Contract: Redocly lint of api/openapi.yaml.

CI uses ubuntu-latest, read-only contents/actions permissions by default, and check-write permission for lint. It publishes no images or job outputs.

Multiarchitecture workspace development image

Mainloop dev image runs on PRs targeting main and pushes to main only when one of these paths changes (no manual trigger):

  • .devcontainer/**, .trunk/**, scripts/with-timeout.mjs
  • package.json, pnpm-lock.yaml, pnpm-workspace.yaml, .npmrc
  • .github/workflows/dev-image.yml

PR-only validate builds .devcontainer/Dockerfile without pushing, separately for linux/amd64 on ubuntu-latest and linux/arm64 on ubuntu-24.04-arm (10 minutes each). Main pushes instead run publish-amd64 and publish-arm64 on those native runners (10 minutes each). Each publishes ghcr.io/oldsj/mainloop-dev by digest and exposes a digest job output.

The dependent merge job (3 minutes, ubuntu-latest) combines both digests into a multiarchitecture index with tags <full commit SHA>, sha-<full commit SHA> and latest. It validates and exposes the index digest, and records the source, tags and immutable image reference in the job summary. This workspace image is distinct from the application images below.

Workspace cache image

The workspace cache image (images/workspace-cache) is no longer built by GitHub Actions. It is built in the cluster that runs the workspaces, by an Argo Workflows CronWorkflow on BuildKit, and published to the cluster's own OCI registry. The workflow and the BuildKit service live in the infrastructure repository (k8s/apps/ci, k8s/apps/buildkit). Workspace nodes then pull the image over the LAN instead of from ghcr, which was too slow from the cluster to start workspaces on a new digest (#274).

Every 30 minutes the workflow clones main and builds the dev image (.devcontainer/Dockerfile) when its inputs change, then the cache image when its inputs (images/workspace-cache/**, server/go.mod, server/go.sum, the pnpm manifests and the dev image digest) or the UTC date change, so it rebuilds once a day otherwise. Builds run natively on an arm64 node and push zstd-compressed OCI layers, which a node unpacks several times faster than gzip.

A smoke step runs the new image by digest on the workspace node: a fresh clone at the commit must build with zero compiles (go build and test binaries) and install the pnpm workspace offline, with each of GOMODCACHE, GOCACHE, npm_config_store_dir and npm_config_virtual_store_dir under /opt/cache. Only then does cache-main move, and only if the commit is still the head of main. Because the smoke step runs on the workspace node, the node already holds the image when environments start following it.

The tags (cache-<sha>, one per build) are not pruned yet.

Production application images

Publish images runs on all pushes to main and manual workflow_dispatch, without path filters. Its publish matrix builds the Go server (server/Dockerfile, prod target) and the React app (web/Dockerfile) on ubuntu-24.04-arm, publishing only linux/arm64 images (15 minutes each):

  • ghcr.io/oldsj/mainloop-backend:<first seven commit SHA characters> (the Go server; the image keeps its historical name because the production manifests pin it)
  • ghcr.io/oldsj/mainloop-frontend:<first seven commit SHA characters>

The frontend uses the workflow's production API build argument. There is no latest tag or job-level output. Step outputs provide the short SHA and build digest; summaries record source, tag, digest and an immutable infrastructure pin. The image jobs are not restricted to main, but the release job is: it runs only on main, and only while its commit is still the tip of main. It force-pushes the release branch and a release-<sha7> tag with the digests pinned in the prod overlay. Argo tracks release; no infrastructure PR is needed per release.

Shared live-development application images

Publish live dev images runs on pushes to main and manual workflow_dispatch, without path filters. Its publish matrix is explicitly restricted to refs/heads/main, including manual runs. It builds the dev target of the Go server and the React app on ubuntu-24.04-arm, publishing only linux/arm64 images (15 minutes each):

  • ghcr.io/oldsj/mainloop-server-dev
  • ghcr.io/oldsj/mainloop-web-dev

Both receive <first seven commit SHA characters> and main tags; main is the mutable one, and the shared mainloop-dev overlay pins it. Step outputs provide the short SHA and digest; summaries record source, tags and digest, with no job-level output. These are application dev targets, not the multiarchitecture workspace image. Publishing them does not start or update the shared instance.

Concurrency and publication boundaries

Each workflow cancels in-progress runs in its own workflow/ref concurrency group (dev-image uses dev-image-${{ github.ref }}). Matrix jobs disable fail-fast so independent builds can finish. Publication jobs have package-write and contents-read permissions; workspace PR validation has contents-read only. Builds use GitHub Actions caches separated by image or architecture. The job timeouts above are limits, not measured runtimes or qualification claims.

About

A single conversation to manage all of your AI sessions - that keeps working while you're away

Resources

Contributing

Stars

7 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages