feat(samples): add self-improving Mastra demo for AWS and GCP#648
Merged
Conversation
Production app (Cloud Run) + live-editable dev service (forced onto Compute Engine via second host-mode port), shared managed Postgres, and a Vertex AI model service for the Mastra coding agent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r glue Hono server (127.0.0.1:4111, container-internal only) hosting a Mastra Agent with Workspace file tools path-scoped to todo-app/. Runs are fire-and-forget with a polled log, and a deterministic tsc --noEmit verify (with one repair round) runs outside the agent's control. Caddy fronts the Next dev server and absorbs its restarts; entrypoint git-inits a runtime baseline so agent edits have history. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ibility pg 8.22+ treats sslmode=require as verify-full and rejects Cloud SQL's internal CA (UNABLE_TO_VERIFY_LEAF_SIGNATURE). Let pg derive TLS behavior from the connection string instead of overriding ssl in code. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ma init - Better Auth: trust proxy headers and disable the origin check for demo mode — the TLS-terminating load balancer made login fail with 'Invalid origin'. Marked TODO(security) for the pre-release security pass. - Serialize ensureSchema() with a pg advisory lock: app + dev racing CREATE TABLE IF NOT EXISTS on a fresh DB hit duplicate pg_type_typname_nsp_index. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… runs on model error gemini-3.5-flash is not a real Vertex publisher model, so the coding agent's Vertex call was rejected by the vertexai.allowedModels org policy. Switch to gemini-3-flash (an allowed, existing model). Also surface model/stream errors as failed runs: previously a model error was logged but the run still typechecked (a no-op, since nothing changed) and reported 'Changes are live', masking the failure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…erved in europe-west2) gemini-3-flash returns 404 NOT_FOUND in europe-west2. gemini-2.5-flash is GA there and validated end-to-end: the coding agent edits app source and the change hot-reloads live. Keeps the London-demo europe-west2 setup. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
raphaeltm
had a problem deploying
to
deploy-changed-samples
July 17, 2026 11:50 — with
GitHub Actions
Failure
…rver The coding agent edits todo-app/ and can break the Next.js dev app, including the admin page used to send fixes to the agent — a deadlock. Move the admin console out of Next.js into the agent server (Hono), which lives outside the agent's editable tree: - agent server now serves /admin (console), /admin/login (break-glass), /admin/dispatch, /admin/runs/:id; reads feedback + validates admins directly against Postgres (pg added to the agent). - Caddy routes /admin* to the agent (:4111), everything else to Next.js (:3001), so the console survives a Next.js crash. - Auth: reuse the better-auth admin login (session validated against Postgres, works while the app is down) + an ADMIN_TOKEN break-glass fallback. - Remove the old Next.js admin page, /api/agent/* routes, and admin-console component so nothing admin-related remains in the agent-editable tree. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…guardrail Deploy 1 of the trustworthy self-updating app: Run history + model + UX fix (agent server): - Persist every run to Postgres (agent_runs): status, full log, model used, timestamps; survives restarts and redeploys. - Admin console gains a 'Recent runs' list (click to view a past run's log + model), client-rendered feedback + runs that refresh after a run — the run log no longer vanishes with nothing to show. - Runs record which model was used (CHAT_MODEL). Automatic guardrail (per product decision: auth-only for now, no approvals): - beforeToolCall hook hard-blocks the agent writing/editing/deleting lib/auth.ts — enforced in code, not just the prompt. Error capture -> backlog (dev and prod): - Server errors (instrumentation onRequestError) and client errors (window listeners + error boundaries) are recorded as 'error' feedback items the admin can dispatch to the agent. Deduped and length-capped. - feedback gains a 'source' column; user_id nullable for system errors. - Friendly error boundaries (error.tsx, global-error.tsx) that report and offer retry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…demand verdict Every successful agent run now commits its edits (scoped to todo-app/) with Run-Id/Feedback-Id/Model trailers pointing at the Postgres rows it addressed; failed runs restore the working tree to the last good commit. Runs are serialized (409 on concurrent dispatch). The admin console gains a History panel (commits cross-linked to runs), an admin-only revert-as-new-commit with a post-revert typecheck report, and an on-demand 'Grade this run' verdict. Durable history plumbing for the upcoming self-publish: .git is no longer dockerignored (it rides the build context into the next dev image, under the 100 MiB limit since heavy dirs are gitignored) and the entrypoint keeps an existing repo instead of re-initializing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…blish interactive login The Publish panel has the dev container run 'defang compose up --detach' on its own Compose project, overwriting both the dev and app services from the live workspace — intentionally no GitOps. Fabric authorization is a fresh interactive 'defang login' per publish: the console surfaces the auth URL in a new tab (the CLI's redirect goes to the auth server and it long-polls for the code, so no callback to this container is needed) and the admin must complete it every time; the token lives in an ephemeral state dir wiped when the publish ends. GCP credentials are the dev service's own service account (deploy roles granted declaratively via x-defang-roles) through the metadata server — no key files anywhere. Publishes are recorded in a deployments table with streamed CLI logs and a publish marker commit (Deployment-Id trailer, authored as the admin); on boot the next container generation marks the deployment live when its HEAD is that publish commit. Runs and publishes are mutually exclusive. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… publishes failed Set the cancelled phase before killing the login/deploy child so their exit handlers no-op instead of overwriting the deployment row with 'failed'. Found by the headless publish-flow validation against the beta stack. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…never parsed CONSOLE_SCRIPT is authored in a TS template literal, so \n escapes in client-facing strings (revert alert, whoami box, publish log tail) were processed server-side into real newlines inside JS string literals. The served script failed to parse (SyntaxError: Invalid or unexpected token), loadData() never ran, and every admin panel hung at 'Loading…' while the endpoints themselves were healthy. - Escape the three occurrences as \\n so the browser receives \n. - Compile CONSOLE_SCRIPT with new Function() at module load, without running it, so a future unparseable console script fails the deploy instead of shipping a dead console. - Surface loadData() failures in the panels instead of silently leaving 'Loading…' forever. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… in admin Publish/deployment logs were already persisted to the deployments table, but the admin console only showed the in-memory logTail while a publish was in the deploying phase — the moment it failed, the panel dropped to just the error banner and the streamed logs vanished, with no way to see why it failed. - Add GET /admin/deployments/:id returning the full persisted log. - Keep the publish list lightweight (drop log bodies from listDeployments, expose length only) so the 2s panel poll stays cheap. - Make every deployment row clickable to open its stored log, and auto-open a failed publish's log so the error is visible in place. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… publish
The publish flow authenticates to GCP keyless via the VM's metadata-server
service account, whose access token carries no email — the stable CLI cannot
resolve the caller principal there ('no email found in token info') and every
publish died at account-info. The fix (DefangLabs/defang#2174, metadata-server
email fallback) is only in the nightly so far.
Resolve the current nightly asset at build time instead of pinning: nightly
assets are replaced daily, so a pinned asset URL would 404 on the next
self-rebuild and brick publishing. TODO: re-pin to the first stable release
containing #2174.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fig listing The first real publish with working GCP identity got past account-info and died at 'failed to list secrets: secretmanager.secrets.list denied' — compose up validates the stack's config (POSTGRES_PASSWORD etc.) by listing its Secret Manager secrets, and the x-defang-roles set predates that path (every earlier deploy ran as an owner-level key, so it was never exercised). Metadata-only viewer is enough: the CLI lists names; the CD (which has secretmanager.admin) reads the values. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
|
Consolidated the cloud configuration in 92ef6c2: AWS and GCP now share the single compose.yaml, compose.dev.yaml remains local-only, and the two stack files select .env.aws/.env.gcp. The provider-specific permission is supplied through the cross-cloud x-defang-policies field, and the private host port is shared (private on AWS; GCE-pinning on GCP). Default/AWS/GCP loader renders, exact two-file layout, agent typecheck, diff check, and an independent elegance review all pass. The PR description is updated; requesting another look. |
lionello
reviewed
Jul 21, 2026
lionello
reviewed
Jul 21, 2026
lionello
temporarily deployed
to
deploy-changed-samples
July 21, 2026 07:41 — with
GitHub Actions
Inactive
lionello
temporarily deployed
to
deploy-changed-samples
July 21, 2026 07:42 — with
GitHub Actions
Inactive
lionello
temporarily deployed
to
deploy-changed-samples
July 21, 2026 07:47 — with
GitHub Actions
Inactive
raphaeltm
temporarily deployed
to
deploy-changed-samples
July 21, 2026 08:37 — with
GitHub Actions
Inactive
Replace the deprecated `provider: type: model` service with a top-level `models:` element plus a `models:` binding on `dev` (matching compose.dev.yaml). Defang synthesizes the LiteLLM gateway from the model entry and injects CHAT_URL / CHAT_MODEL / OPENAI_API_KEY into the binding service, so the agent wiring is unchanged. Also drops the dead `OPENAI_API_KEY: defang` that was set on the old gateway service. The top-level `models:` element cannot express per-service gateway memory, so the gateway now uses the CLI default on both clouds instead of the former per-cloud 2 GiB (AWS) / 512 MiB (GCP). Removed the now-unused CHAT_MEMORY from .env.aws / .env.gcp and the gateway-memory column from the README, and refreshed README + agent/src/model.ts wording that described chat as a "model-provider service". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename the sample to "Self-Improving Mastra": directory, compose project names, the 1-click deploy template URL, agent package name and git identity, in-app titles and prose, and the root samples-table entry. No behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The deploy-changed-samples staging filter excluded the BYOC-only sample by its old directory name; the rename left it deploying (and failing on missing ADMIN_TOKEN). Update the awk filter to self-improving-mastra so it is skipped again (it exceeds the retired Playground staging quota). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
lionello
approved these changes
Jul 21, 2026
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a self-updating Mastra demo with a public production app and a gated,
always-on development environment. The coding agent edits in an isolated git
worktree, typechecks, and applies successful changes atomically; the admin can
review history, reboot to the published image, and explicitly publish from
inside the dev container.
Cloud deployments share one
compose.yaml;compose.dev.yamlis only forlocal Docker development. The two committed stacks select non-secret env files:
aws.env.awsAdministratorAccesschat-default, 2 GiBgcp.env.gcproles/ownerchat-default, 512 MiB.defang/awsand.defang/gcpuse the mergedCOMPOSE_ENV_FILESstacksupport. Secrets remain in Defang config, and cloud credentials come from the
devworkload's ambient identity.Cloud behavior
devkeeps the editable GCP workspace on one ComputeEngine VM instead of a scale-to-zero Cloud Run service. It remains private on
AWS and does not create another public endpoint.
x-defang-policiesis cross-cloud: the selected env file supplies the AWSmanaged-policy ARN or GCP project role used by admin-triggered self-publish.
settings stay together.
gateway while GCP uses 512 MiB.
Verification
chat-default, 1 GiB validation fallbackaws, 2 GiB gateway, full AWS managed-policy ARNgcp, 512 MiB gateway,roles/ownercompose.yamlandcompose.dev.yamlnpm run typecheckinagent/git diff --check200
zso8kk4t6qmw: clean four-service deployment; app and devhealth endpoints returned 200 and
/adminremained gatedThe current single-Compose head has exact loader coverage for both stacks. A
fresh live deployment of this final consolidation remains to be run on each
cloud.
Samples Checklist
✅ All good!