Skip to content

[feat] Build and ship the mobile gh image (4/12) - #5683

Open
ardaerzin wants to merge 8 commits into
feat/agenta-chat-packagefrom
feat/mobile-image-and-ci
Open

[feat] Build and ship the mobile gh image (4/12)#5683
ardaerzin wants to merge 8 commits into
feat/agenta-chat-packagefrom
feat/mobile-image-and-ci

Conversation

@ardaerzin

Copy link
Copy Markdown
Contributor

Context

Lane 1 added the mobile app's production Dockerfile but deliberately left it unwired ("build wiring follows"). This lane connects it, so /m can actually ship in a gh image.

Changes

A CI workflow runs the mobile typecheck and builds the gh image on changes under web/mobile. The web-mobile service joins the gh compose stacks for both editions. The mobile skills are allowlisted in .gitignore, which otherwise ignores everything under .claude/skills.

Tests / notes

  • The rollout order is written down in docs/design/agenta-mobile/plans/2026-07-25-wp1-infra-tail.md: the image builds before anything routes to it, so a half-deployed stack never serves a 502 at /m.
  • Nothing here changes desktop images or their build.

@vercel

vercel Bot commented Aug 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview Aug 5, 2026 5:53pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 52b997ab-1080-4c11-9a2f-b386590dc9e1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added optional mobile web access at /m for supported local and hosted deployments.
    • Added configuration options for selecting the mobile image and tag.
    • Added a startup option to enable the mobile web service.
    • Added HTTP/HTTPS routing and automatic service restart support.
  • Documentation

    • Added a mobile project guide covering capabilities, setup, verification, and follow-up work.
  • Tests

    • Added automated mobile checks for builds, routing, image execution, and multi-platform publishing.

Walkthrough

Added mobile CI checks, multi-architecture image builds, smoke tests, optional Compose deployment at /m, profile control, handoff documentation, and workspace ignore rules.

Changes

Mobile CI and deployment

Layer / File(s) Summary
Mobile image CI pipeline
.github/workflows/17-check-mobile.yml
The workflow typechecks mobile packages, validates image metadata, builds amd64 and arm64 images, runs /m smoke tests, verifies non-root execution, reports image details, and optionally publishes manifests.
Compose mobile service integration
hosting/docker-compose/*, hosting/docker-compose/run.sh
Compose files define profile-gated web-mobile services with configurable images, shared environments, port 3000, and Traefik /m routes. run.sh enables the profile with --with-mobile during startup and shutdown.
Mobile project handoff and workspace support
docs/design/agenta-mobile/README.md, .gitignore
The handoff document records mobile architecture, implementation status, verification commands, deployment requirements, and follow-up tracks. Mobile agent skill directories are ignored.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PullRequest
  participant GitHubActions
  participant Buildx
  participant GHCR
  participant MobileContainer
  PullRequest->>GitHubActions: trigger mobile checks
  GitHubActions->>GitHubActions: typecheck mobile packages and validate image metadata
  GitHubActions->>Buildx: build amd64 and arm64 images
  Buildx->>GHCR: publish images and architecture caches when enabled
  GitHubActions->>MobileContainer: run mobile route and user smoke tests
  GitHubActions->>GHCR: merge architecture images when enabled
Loading
sequenceDiagram
  participant RunScript as run.sh
  participant Compose
  participant WebMobile as web-mobile
  participant Traefik
  RunScript->>Compose: enable with-web-mobile profile
  Compose->>WebMobile: start mobile server on port 3000
  Traefik->>WebMobile: route /m traffic without path stripping
  RunScript->>Compose: include with-web-mobile during shutdown
Loading

Possibly related PRs

  • Agenta-AI/agenta#5679: Extends the mobile app infrastructure with production deployment, CI image builds, and runtime controls.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: building and shipping the mobile GH image.
Description check ✅ Passed The description directly explains the mobile image build, CI workflow, Compose integration, and rollout documentation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 60.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/mobile-image-and-ci

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ardaerzin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (1)
.github/workflows/17-check-mobile.yml (1)

44-44: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Set persist-credentials: false on each checkout.

None of the three actions/checkout@v6 steps (lines 44, 73, 119) disable credential persistence. Static analysis (zizmor) flags this as artipacked: the job's git credentials remain on disk and can leak if a later step or a compromised action touches the working tree. Since no step in this workflow needs git push, disable persistence on all three checkouts.

🔒 Proposed fix
       - uses: actions/checkout@v6
+        with:
+          persist-credentials: false

(apply the same with: block at all three occurrences)

Also applies to: 73-73, 119-119

Source: Linters/SAST tools


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ecd8f93a-d0d9-49cc-a5a3-a16793702491

📥 Commits

Reviewing files that changed from the base of the PR and between 2bdbdca and 85f8fd4.

📒 Files selected for processing (11)
  • .github/workflows/17-check-mobile.yml
  • .gitignore
  • docs/design/agenta-mobile/README.md
  • hosting/docker-compose/ee/docker-compose.gh.local.yml
  • hosting/docker-compose/ee/docker-compose.gh.yml
  • hosting/docker-compose/ee/env.ee.gh.example
  • hosting/docker-compose/oss/docker-compose.gh.local.yml
  • hosting/docker-compose/oss/docker-compose.gh.ssl.yml
  • hosting/docker-compose/oss/docker-compose.gh.yml
  • hosting/docker-compose/oss/env.oss.gh.example
  • hosting/docker-compose/run.sh

Comment thread .github/workflows/17-check-mobile.yml Outdated
Comment thread .github/workflows/17-check-mobile.yml
Comment thread docs/design/agenta-mobile/README.md
Comment on lines +39 to +43
| [plans/2026-07-26-wp5-device-gate.md](./plans/2026-07-26-wp5-device-gate.md) | WP5 device gate (flag-gated middleware, both directions) — **READY TO EXECUTE**; default-off, T8 banner-retirement deferred to flag-flip |

Wave-2 plans (WP2 auth + project drawer, WP3b mobile chat skin, WP4 product pages, WP5 device
gate) are **deliberately unwritten** — they must be planned against the real wave-1 code and the
finalized sessions surface.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Make the WP5 planning status consistent.

Line 39 marks the WP5 plan as READY TO EXECUTE. Lines 41-43 state that the WP5 plan is deliberately unwritten. Keep one status.

Comment on lines +162 to +167
```bash
cd web && pnpm install
pnpm --filter @agenta/mobile lint # bans + tokens:check
pnpm --filter @agenta/mobile types:check
pnpm build-mobile && test -f web/../web/mobile/.next/standalone/mobile/server.js
pnpm dev-mobile # → http://localhost:3000/m, check light+dark

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix the standalone-file check path.

After cd web on Line 163, Line 166 resolves web/../web/mobile/... to web/web/mobile/.... The check fails after a valid build.

Proposed fix
-pnpm build-mobile && test -f web/../web/mobile/.next/standalone/mobile/server.js
+pnpm build-mobile && test -f mobile/.next/standalone/mobile/server.js
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```bash
cd web && pnpm install
pnpm --filter @agenta/mobile lint # bans + tokens:check
pnpm --filter @agenta/mobile types:check
pnpm build-mobile && test -f web/../web/mobile/.next/standalone/mobile/server.js
pnpm dev-mobile # → http://localhost:3000/m, check light+dark

Comment on lines +186 to +189
- **Chores pending:** `.gitignore` allowlist entries for the `mobile-*` skills (they're tracked
via `git add -f`, matching repo precedent — new files inside them would be invisible to
`git status` until allowlisted); Fern regen so the FE `include_ended` param stops being a
runtime cast.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the completed .gitignore chore.

These lines mark the mobile skill allowlists as pending, but this change adds those allowlists in .gitignore Lines 103-105 and 130-132. Mark the chore complete or remove it.

@ardaerzin

Copy link
Copy Markdown
Contributor Author

Both workflow findings were real and are fixed at the commit that introduced the file.

Least privilege. packages: write sat at workflow level, so typecheck and prepare carried registry push scope they never use. It now sits on the only two jobs that authenticate to the registry (build-image, merge-manifests).

Script injection. INPUT_TAG="${{ inputs.image_tag }}" interpolated a workflow_dispatch string directly into a shell script. The expression is substituted before bash parses the line, so the value could close the quote and run commands. The inputs now arrive through env: and are referenced as "$INPUT_TAG" / "$INPUT_PUSH", where they are only ever data. YAML re-parsed to confirm the structure still resolves.

The four README findings are docs accuracy. I have applied the one that mattered outside this PR (a machine-specific absolute path in the WP3a plan, which leaked one developer's checkout into the repo); the remaining status/wording reconciliations are tracked but not yet applied.

@ardaerzin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (4)
.github/workflows/17-check-mobile.yml (1)

94-106: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Validate TAG before publishing it as a job output.

INPUT_TAG is safe in this shell step, but TAG later re-enters shell source through expressions such as Line 164. A dispatch value containing a quote and shell syntax can execute in the build-image job, which has packages: write.

Reject invalid Docker tags before writing image_tag to $GITHUB_OUTPUT. This also rejects newline-based output injection.

Proposed fix
           else
             TAG="${INPUT_TAG:-manual-${SHA}}"
             PUSH="$INPUT_PUSH"
+            if ! [[ "$TAG" =~ ^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$ ]]; then
+              echo "::error::image_tag is not a valid Docker tag"
+              exit 1
+            fi
             REF="$(printf "%s" "${GITHUB_REF_NAME}" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9._-' '-')"

Source: Linters/SAST tools

docs/design/agenta-mobile/README.md (3)

39-43: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use one WP5 planning status.

Line 39 states that the WP5 plan is ready to execute. Lines 41-43 state that WP5 is deliberately unwritten. Update one statement so the runbook has one status.


162-167: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the standalone-file path.

After cd web, the current path resolves to web/web/mobile/.next/.... The verification command fails after a valid build.

-pnpm build-mobile && test -f web/../web/mobile/.next/standalone/mobile/server.js
+pnpm build-mobile && test -f mobile/.next/standalone/mobile/server.js

186-189: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the completed mobile-skill allowlist chore.

This PR adds the .gitignore allowlist entries for mobile-* skills. Do not list that work as pending.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bb9a0966-ca0f-47ff-87ee-e001112dc9c8

📥 Commits

Reviewing files that changed from the base of the PR and between 85f8fd4 and 9629004.

📒 Files selected for processing (11)
  • .github/workflows/17-check-mobile.yml
  • .gitignore
  • docs/design/agenta-mobile/README.md
  • hosting/docker-compose/ee/docker-compose.gh.local.yml
  • hosting/docker-compose/ee/docker-compose.gh.yml
  • hosting/docker-compose/ee/env.ee.gh.example
  • hosting/docker-compose/oss/docker-compose.gh.local.yml
  • hosting/docker-compose/oss/docker-compose.gh.ssl.yml
  • hosting/docker-compose/oss/docker-compose.gh.yml
  • hosting/docker-compose/oss/env.oss.gh.example
  • hosting/docker-compose/run.sh
🚧 Files skipped from review as they are similar to previous changes (9)
  • hosting/docker-compose/ee/env.ee.gh.example
  • hosting/docker-compose/oss/docker-compose.gh.yml
  • hosting/docker-compose/oss/env.oss.gh.example
  • hosting/docker-compose/ee/docker-compose.gh.yml
  • hosting/docker-compose/oss/docker-compose.gh.local.yml
  • hosting/docker-compose/run.sh
  • hosting/docker-compose/oss/docker-compose.gh.ssl.yml
  • .gitignore
  • hosting/docker-compose/ee/docker-compose.gh.local.yml

Comment thread .github/workflows/17-check-mobile.yml Outdated
@ardaerzin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@ardaerzin

Copy link
Copy Markdown
Contributor Author

Assert the exact root status — real, fixed. curl -sf fails on 4xx and 5xx alike, so the check treated a 500 root as a pass. It now compares the status code itself and dumps the container log when it is anything but 404.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e8b8da7f-2348-431b-b4e1-f84dfe6d55b8

📥 Commits

Reviewing files that changed from the base of the PR and between 9629004 and 2f47ef7.

📒 Files selected for processing (11)
  • .github/workflows/17-check-mobile.yml
  • .gitignore
  • docs/design/agenta-mobile/README.md
  • hosting/docker-compose/ee/docker-compose.gh.local.yml
  • hosting/docker-compose/ee/docker-compose.gh.yml
  • hosting/docker-compose/ee/env.ee.gh.example
  • hosting/docker-compose/oss/docker-compose.gh.local.yml
  • hosting/docker-compose/oss/docker-compose.gh.ssl.yml
  • hosting/docker-compose/oss/docker-compose.gh.yml
  • hosting/docker-compose/oss/env.oss.gh.example
  • hosting/docker-compose/run.sh
🚧 Files skipped from review as they are similar to previous changes (9)
  • hosting/docker-compose/ee/env.ee.gh.example
  • hosting/docker-compose/oss/docker-compose.gh.ssl.yml
  • hosting/docker-compose/oss/env.oss.gh.example
  • hosting/docker-compose/run.sh
  • hosting/docker-compose/oss/docker-compose.gh.yml
  • hosting/docker-compose/ee/docker-compose.gh.local.yml
  • hosting/docker-compose/ee/docker-compose.gh.yml
  • hosting/docker-compose/oss/docker-compose.gh.local.yml
  • .gitignore

Comment thread .github/workflows/17-check-mobile.yml
@ardaerzin
ardaerzin force-pushed the feat/agenta-chat-package branch from 6e2e450 to 854acef Compare August 3, 2026 22:29
@ardaerzin
ardaerzin force-pushed the feat/mobile-image-and-ci branch from 2f47ef7 to d395582 Compare August 3, 2026 22:29
@ardaerzin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bf364e75-36cd-475b-891b-76fcdaf0e343

📥 Commits

Reviewing files that changed from the base of the PR and between 2f47ef7 and d395582.

📒 Files selected for processing (11)
  • .github/workflows/17-check-mobile.yml
  • .gitignore
  • docs/design/agenta-mobile/README.md
  • hosting/docker-compose/ee/docker-compose.gh.local.yml
  • hosting/docker-compose/ee/docker-compose.gh.yml
  • hosting/docker-compose/ee/env.ee.gh.example
  • hosting/docker-compose/oss/docker-compose.gh.local.yml
  • hosting/docker-compose/oss/docker-compose.gh.ssl.yml
  • hosting/docker-compose/oss/docker-compose.gh.yml
  • hosting/docker-compose/oss/env.oss.gh.example
  • hosting/docker-compose/run.sh
🚧 Files skipped from review as they are similar to previous changes (9)
  • hosting/docker-compose/ee/env.ee.gh.example
  • .gitignore
  • hosting/docker-compose/oss/env.oss.gh.example
  • hosting/docker-compose/oss/docker-compose.gh.ssl.yml
  • hosting/docker-compose/ee/docker-compose.gh.yml
  • hosting/docker-compose/run.sh
  • hosting/docker-compose/oss/docker-compose.gh.local.yml
  • hosting/docker-compose/oss/docker-compose.gh.yml
  • hosting/docker-compose/ee/docker-compose.gh.local.yml

Comment on lines +176 to +202
- name: Smoke-test the image serves /m
run: |
IMAGE="ghcr.io/agenta-ai/agenta-web-mobile:${{ needs.prepare.outputs.image_tag }}-${{ matrix.arch }}"
if [ "${{ needs.prepare.outputs.push }}" = "true" ]; then
docker pull "$IMAGE"
fi
docker run -d --name mobile-smoke -p 3000:3000 "$IMAGE"
for i in $(seq 1 30); do
if curl -sf http://127.0.0.1:3000/m >/dev/null; then break; fi
sleep 1
done
# Assert the status itself rather than curl's exit code: `-sf` succeeds on a 3xx
# (the page never rendered) and fails identically on 404 and 500.
expect_status() {
local path="$1" want="$2" got
got="$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:3000${path}")"
if [ "$got" != "$want" ]; then
echo "::error::expected ${path} to return ${want}, got ${got}"
docker logs mobile-smoke
exit 1
fi
}
expect_status /m 200
expect_status /m/__env.js 200
# basePath /m owns the prefix, so the bare root belongs to nothing.
expect_status / 404
docker rm -f mobile-smoke

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Bound and handle smoke-test HTTP requests.

The curl calls at Line 184 and Line 191 have no connection or total timeout. If the container accepts a connection but does not respond, one request can block the job indefinitely.

At Line 191, a connection failure can terminate the script before docker logs mobile-smoke runs. Convert transport failures to a status value so the existing diagnostic path runs.

Proposed fix
           docker run -d --name mobile-smoke -p 3000:3000 "$IMAGE"
           for i in $(seq 1 30); do
-            if curl -sf http://127.0.0.1:3000/m >/dev/null; then break; fi
+            if curl --connect-timeout 2 --max-time 5 -sf http://127.0.0.1:3000/m >/dev/null; then break; fi
             sleep 1
           done
           # Assert the status itself rather than curl's exit code: `-sf` succeeds on a 3xx
           # (the page never rendered) and fails identically on 404 and 500.
           expect_status() {
             local path="$1" want="$2" got
-            got="$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:3000${path}")"
+            if ! got="$(curl --connect-timeout 2 --max-time 5 -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:3000${path}")"; then
+              got="000"
+            fi
             if [ "$got" != "$want" ]; then
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Smoke-test the image serves /m
run: |
IMAGE="ghcr.io/agenta-ai/agenta-web-mobile:${{ needs.prepare.outputs.image_tag }}-${{ matrix.arch }}"
if [ "${{ needs.prepare.outputs.push }}" = "true" ]; then
docker pull "$IMAGE"
fi
docker run -d --name mobile-smoke -p 3000:3000 "$IMAGE"
for i in $(seq 1 30); do
if curl -sf http://127.0.0.1:3000/m >/dev/null; then break; fi
sleep 1
done
# Assert the status itself rather than curl's exit code: `-sf` succeeds on a 3xx
# (the page never rendered) and fails identically on 404 and 500.
expect_status() {
local path="$1" want="$2" got
got="$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:3000${path}")"
if [ "$got" != "$want" ]; then
echo "::error::expected ${path} to return ${want}, got ${got}"
docker logs mobile-smoke
exit 1
fi
}
expect_status /m 200
expect_status /m/__env.js 200
# basePath /m owns the prefix, so the bare root belongs to nothing.
expect_status / 404
docker rm -f mobile-smoke
- name: Smoke-test the image serves /m
run: |
IMAGE="ghcr.io/agenta-ai/agenta-web-mobile:${{ needs.prepare.outputs.image_tag }}-${{ matrix.arch }}"
if [ "${{ needs.prepare.outputs.push }}" = "true" ]; then
docker pull "$IMAGE"
fi
docker run -d --name mobile-smoke -p 3000:3000 "$IMAGE"
for i in $(seq 1 30); do
if curl --connect-timeout 2 --max-time 5 -sf http://127.0.0.1:3000/m >/dev/null; then break; fi
sleep 1
done
# Assert the status itself rather than curl's exit code: `-sf` succeeds on a 3xx
# (the page never rendered) and fails identically on 404 and 500.
expect_status() {
local path="$1" want="$2" got
if ! got="$(curl --connect-timeout 2 --max-time 5 -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:3000${path}")"; then
got="000"
fi
if [ "$got" != "$want" ]; then
echo "::error::expected ${path} to return ${want}, got ${got}"
docker logs mobile-smoke
exit 1
fi
}
expect_status /m 200
expect_status /m/__env.js 200
# basePath /m owns the prefix, so the bare root belongs to nothing.
expect_status / 404
docker rm -f mobile-smoke
🧰 Tools
🪛 zizmor (1.28.0)

[info] 178-178: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[info] 179-179: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

Comment on lines +47 to +49
Branch **`feat/agenta-mobile-wave-1`** (off `feat/sessions-continuity-fixes`, worktree
`.claude/worktrees/big-agents-sessions`). Not pushed. Executed subagent-driven: every task got a
fresh implementer + spec-compliance review + code-quality review; fix rounds were re-reviewed.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the stale local branch state from the committed handoff.

This file is committed in the current pull request, but Lines 47-49 still state that feat/agenta-mobile-wave-1 is “Not pushed” and reference a local worktree. Replace this with the current repository state or mark it as historical.

@ardaerzin
ardaerzin force-pushed the feat/agenta-chat-package branch from 854acef to 7b120cf Compare August 4, 2026 18:25
@ardaerzin
ardaerzin force-pushed the feat/mobile-image-and-ci branch from d395582 to 4c31b88 Compare August 4, 2026 18:25
@ardaerzin
ardaerzin force-pushed the feat/agenta-chat-package branch from 7b120cf to e007054 Compare August 4, 2026 19:26
@ardaerzin
ardaerzin force-pushed the feat/mobile-image-and-ci branch from 4c31b88 to beca6ec Compare August 4, 2026 19:26
@mmabrouk
mmabrouk marked this pull request as ready for review August 5, 2026 08:22
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. ci/cd devops labels Aug 5, 2026

@mmabrouk mmabrouk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤖 The AI agent says:

@ardaerzin, this review found four issues in the mobile image and hosting path:

  • P1: A manual push can publish an image even when the dedicated typecheck fails.
  • P1: A draft PR head can remain unvalidated after the PR becomes ready for review.
  • P2: --nginx --with-mobile starts the mobile service but does not route /m to it.
  • P2: A stalled smoke-test HTTP response can hang the job and bypass container logs on transport failure.

I added the details and suggested fix direction inline.

Comment thread .github/workflows/17-check-mobile.yml Outdated
contents: read
packages: write
name: build-image
needs: prepare

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤖 The AI agent says:

[P1] Gate image publication on the typecheck job

During workflow_dispatch with push=true, this job only needs prepare, so it can build and push independently of typecheck. Because web/mobile/next.config.ts sets typescript.ignoreBuildErrors: true, the build and smoke test can succeed while the dedicated typecheck fails, and merge-manifests can still publish the invalid tag or overwrite latest. Please add typecheck to the image publication dependency path, for example by making build-image need both prepare and typecheck.

jobs:
typecheck:
name: Mobile types
if: github.event_name == 'workflow_dispatch' || !github.event.pull_request.draft

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤖 The AI agent says:

[P1] Run checks when a draft becomes ready

If a commit is pushed while the PR is a draft, this condition skips both entry jobs. The default pull_request activity types do not include ready_for_review, so marking that PR ready does not validate the existing head. Please include ready_for_review in the trigger activity types or allow the checks to run for draft events.

fi

if $WITH_MOBILE; then
COMPOSE_CMD+=" --profile with-web-mobile"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤖 The AI agent says:

[P2] Route mobile traffic when nginx is selected

run.sh --oss --gh --nginx --with-mobile activates web-mobile, but that service only has Traefik labels. The OSS nginx config sends /m through its catch-all to web, so the advertised endpoint never reaches the mobile container. Please add an nginx /m route or reject the nginx and mobile flag combination.

Comment thread .github/workflows/17-check-mobile.yml Outdated
# (the page never rendered) and fails identically on 404 and 500.
expect_status() {
local path="$1" want="$2" got
got="$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:3000${path}")"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤖 The AI agent says:

[P2] Bound every smoke-test HTTP request

These status requests and the readiness request above have no connection or total timeout. A container that accepts a connection but never responds can therefore hang the job. Also, a transport failure in this command substitution exits the Actions bash script under -e before docker logs mobile-smoke runs. Please add bounded connect and total timeouts, and convert transport failures into a diagnostic status that reaches the log path.

mobile-app-structure, mobile-shadcn-conventions, and mobile-motion-patterns
are already tracked via force-add; allowlist them so future files inside
(e.g. references/) stay visible to git status.
Also runs types:check for @agenta/chat alongside @agenta/mobile in the
typecheck job: verified locally (pnpm turbo run types:check --filter=@agenta/chat
exits 0, pulling in @agenta/shared/entities/playground via turbo dependsOn).
Add an opt-in web-mobile service (with-web-mobile profile) to the five
prod/gh compose files (oss gh/gh.ssl/gh.local, ee gh/gh.local), plus the
AGENTA_WEB_MOBILE_IMAGE_NAME/TAG env-example entries. run.sh gains
--with-mobile to activate the profile and reap it on shutdown.
The image smoke test asserts that the bare root 404s, because basePath /m owns
the prefix. It did so by treating a successful `curl -sf` as the failure, but
`curl -sf` fails on every 4xx and 5xx alike. A root that returned 500 read as a
pass. Compare the status code itself, and dump the container log when it is
anything other than 404.
…he /m segment

Three findings from the same review, all in how this workflow and its compose siblings treat
untrusted or ambiguous input.

`image_tag` comes from workflow_dispatch and was written to GITHUB_OUTPUT unchecked, then
interpolated into later run: blocks as an image name. It is now rejected unless it is a Docker
tag. The check is a case statement rather than a grep because grep matches per line: a value
containing a newline passes a line-based check and forges a second step output.

The smoke test asserted curl's exit code, which cannot tell 404 from 500 and succeeds on a 3xx
that never rendered a page. It now asserts each status directly: 200 for /m and /m/__env.js, 404
for the bare root.

The five gh/ssl compose files routed the mobile app with PathPrefix(`/m`), which also matches
/mobile, /metrics and anything else whose first two characters are /m, taking those paths from
the web catch-all. They now use the segment-exact form the dev compose files already had.
…quests

Three defects in the image workflow, all on the path that publishes a tag.

`build-image` needed only `prepare`. `web/mobile/next.config.ts` sets
`typescript.ignoreBuildErrors: true`, so the build and the smoke test can both pass while the
dedicated typecheck fails — a dispatch with `push=true` would publish that tag and
`merge-manifests` could move `latest` onto it. It now needs `typecheck` as well.

`ready_for_review` is not a default `pull_request` activity type, and both entry jobs skip while
a PR is a draft. Commits pushed during draft were therefore never checked, and marking the PR
ready validated nothing. It is now in the trigger list.

The smoke requests had no timeouts, so a container that accepts a connection and never answers
hung the job until the 30-minute limit. They are bounded now. A transport failure also used to
exit the step under `set -e` before `docker logs` ran, taking the only diagnostic with it; it
becomes a sentinel status that reaches the mismatch branch instead.
`run.sh --oss --gh --nginx --with-mobile` starts `web-mobile`, but that service carries only
Traefik labels. Under nginx the OSS config sent `/m` through its catch-all to `web`, so the
endpoint the run advertised never reached the mobile container.

`location = /m` plus `location /m/` is nginx's spelling of the Traefik rule the same service
already has: segment-exact, so `/models` keeps falling through to the catch-all.

The upstream goes through a variable rather than a literal host. nginx resolves literal
upstreams at startup, so naming `web-mobile` directly would stop the whole proxy from booting
on any stack started WITHOUT the with-web-mobile profile. Through a variable the lookup is per
request against the resolver the file already declares.

Verified against a real nginx container on a stub network:

    /m, /m/, /m/sessions  -> the mobile upstream
    /models, /mobile, /   -> web, unchanged

and with no `web-mobile` container present at all, nginx still starts, `/` still serves, and
only `/m` answers 502.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd devops size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants