Skip to content

feat(#926): version chip + git build provenance in NavBar/Settings - #931

Merged
vybe merged 1 commit into
devfrom
feature/926-version-build-info
May 26, 2026
Merged

vybe merged 1 commit into
devfrom
feature/926-version-build-info

Conversation

@dolho

@dolho dolho commented May 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Operators couldn't tell which commit was running without SSH'ing to the host or docker inspect. GET /api/version only returned the semver string plus an optional BUILD_DATE env var — no commit/branch surface, no in-app build info. This bakes the local git state into the backend image at build time and renders it in NavBar + Settings.

Changes

Backend

  • Extracted _build_version_payload() from the /api/version handler as a pure helper so unit tests can drive it without main.py's full router graph (opentelemetry, slack_sdk, twilio, …).
  • /api/version now returns git_commit, git_commit_short (first 8), git_commit_subject, git_commit_timestamp, git_branch, build_date. Everything defaults to "unknown" when build args are absent (local volume-mount workflows).
  • Endpoint stays JWT-authenticated (SEC-180).

Build wiring

  • docker/backend/Dockerfile accepts GIT_COMMIT, GIT_COMMIT_SUBJECT, GIT_COMMIT_TIMESTAMP, GIT_BRANCH, BUILD_DATE as ARGs and re-exports each as ENV.
  • docker-compose.yml backend.build.args block forwards the shell vars from the environment so docker compose build picks them up without explicit --build-arg flags.
  • scripts/deploy/start.sh exports the args from the local repo via git rev-parse HEAD / git log -1 --pretty=%cI / etc., gated on git rev-parse --is-inside-work-tree so CI tarball installs still build cleanly.

Frontend

  • composables/useBuildInfo.js — singleton fetch of /api/version cached in module scope; build metadata never changes at runtime.
  • NavBar.vue renders a small muted version chip (v0.9.0 · abcd1234). Click opens a modal with full commit/branch/build-date details.
  • Settings.vue General tab gets a "Build Info" section with the same payload rendered as a dl grid.

Tests

tests/unit/test_926_version_endpoint.py — 3 pass. Exercises _build_version_payload directly with patched env vars to verify:

Test extracts the helper by slicing the source (no full main.py import) so it stays venv-light. Sys.modules lint baseline unchanged.

Live verification

$ docker compose build backend && docker compose up -d --force-recreate backend
$ curl -s -H "Authorization: Bearer $TOKEN" http://localhost:8000/api/version | jq
{
  "version": "0.9.0",
  "platform": "trinity",
  "build_date": "2026-05-25T10:20:57Z",
  "git_commit": "33da38cef66e97a5a9959267bdb42ea599a43951",
  "git_commit_short": "33da38ce",
  "git_commit_subject": "chore(.claude): bump submodule…",
  "git_commit_timestamp": "2026-05-24T18:41:45+01:00",
  "git_branch": "feature/926-version-build-info",
  ...
}

NavBar chip + Settings panel render correctly via Vite hot-reload.

Test plan

  • Unit tests pass locally
  • Live verify against rebuilt backend
  • CI green
  • Manual: confirm chip in production build shows the right commit
  • Manual: confirm modal renders + Settings General tab Build Info section

Files

  • src/backend/main.py — extracted _build_version_payload, extended /api/version (+35/-5)
  • docker/backend/Dockerfile — ARG/ENV block (+17)
  • docker-compose.yml — backend.build.args (+10)
  • scripts/deploy/start.sh — export git vars (+13)
  • src/frontend/src/composables/useBuildInfo.js — singleton cache (new, +45)
  • src/frontend/src/components/NavBar.vue — version chip + modal (+73)
  • src/frontend/src/views/Settings.vue — Build Info section (+56)
  • docs/memory/architecture.md — /api/version row updated
  • docs/memory/requirements.md — §35 Build Info Surface (+58)
  • tests/unit/test_926_version_endpoint.py — 3 tests (new)

Out of scope (per issue body)

  • Per-component version drift (frontend vs backend)
  • MCP server version surface (TypeScript package has its own version)
  • Agent base-image commit metadata

Closes will be set on merge.

Related to #926.

🤖 Generated with Claude Code

@dolho

dolho commented May 25, 2026

Copy link
Copy Markdown
Contributor Author
image

@dolho
dolho requested a review from vybe May 25, 2026 10:36
Operators couldn't tell which commit was running without SSH'ing to the
host or `docker inspect`. `GET /api/version` only had the semver string
plus an optional `BUILD_DATE` env var — no commit/branch surface, no
in-app build info. This bakes the local git state into the backend
image at build time and renders it in two places:

Backend:
- `_build_version_payload()` extracted from the `/api/version` handler
  as a pure helper so unit tests can drive it without main.py's full
  router graph (opentelemetry, slack_sdk, twilio, …).
- Endpoint now returns `git_commit`, `git_commit_short` (first 8),
  `git_commit_subject`, `git_commit_timestamp`, `git_branch`,
  `build_date`. Everything defaults to `"unknown"` when build args
  are absent (local volume-mount workflows).
- Endpoint stays JWT-authenticated (SEC-180).

Build wiring:
- `docker/backend/Dockerfile` accepts `GIT_COMMIT`,
  `GIT_COMMIT_SUBJECT`, `GIT_COMMIT_TIMESTAMP`, `GIT_BRANCH`,
  `BUILD_DATE` as `ARG`s and re-exports each as `ENV`.
- `docker-compose.yml` `backend.build.args` block forwards the
  shell vars from the environment so `docker compose build` picks
  them up without explicit `--build-arg` flags.
- `scripts/deploy/start.sh` exports the args from the local repo
  via `git rev-parse HEAD` / `git log -1 --pretty=%cI` / etc.,
  gated on `git rev-parse --is-inside-work-tree` so CI tarball
  installs still build cleanly.

Frontend:
- `composables/useBuildInfo.js` — singleton fetch of `/api/version`
  cached in module scope; build metadata never changes at runtime.
- `NavBar.vue` renders a small muted version chip (`v0.9.0 · abcd1234`).
  Click opens a modal with full commit/branch/build-date details.
- `Settings.vue` General tab gets a "Build Info" section with the
  same payload rendered as a dl grid.

Tests: `tests/unit/test_926_version_endpoint.py` — 3 pass.
Exercises `_build_version_payload` directly with patched env vars to
verify (a) all five new fields present when ENV set, (b) "unknown"
fallback when ENV missing, (c) pre-#926 fields preserved.

Live-verified: `curl /api/version` against the rebuilt backend returns
the new fields, frontend chip + Settings panel render correctly.

Related to #926.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vybe
vybe force-pushed the feature/926-version-build-info branch from e9370fd to ffb6e58 Compare May 26, 2026 12:02

@vybe vybe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Rebased on dev (resolved §35 numbering collision with #929 — now §36 Build Info Surface) and force-pushed.

Approval gated on CI re-run. One follow-up nit (not blocking): extract _build_version_payload into src/backend/version_info.py so tests/unit/test_926_version_endpoint.py can import it cleanly instead of source-slicing on \n\n\n. Works today but couples the test to PEP 8 spacing inside the helper.

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