Repository navigation
Mecatl Studio maintainability: design alignment, agent contract, test coverage, app structure, and configuration #1774
Description
User story
As an engineer — and as a coding agent — picking up Mecatl Studio after the in-repo bootstrap
stack has landed, I want the app to look like the approved design, carry its own agent
contract, be covered by browser and unit proofs, sit in a folder structure that scales
past the skeleton, and expose one coherent configuration surface, so that Studio is
maintainable by the whole team instead of only by its author.
Companion to #1736. That story brings Studio into the repository as apps/ and ships its
image; this one makes the result maintainable. It does not block #1736's stack (#1746–#1752) —
it starts as that stack lands, axis by axis.
Scope
1. Align Studio UI and design (UX, UI, components, colors, CSS)
- Active: implementation is split into Mecatl Studio: bring the web UI into the repository as apps/ and release its image #1736 sub-issues Studio appearance: design tokens, palettes, typography, and shared controls #1843–Studio Labs: local demo chat and mock Projects tour #1856. Studio design review and parity tracking #1779 owns
the component/token gap inventory and maintainer design review. - Scope includes navigation and interaction flows, page layouts, typography, shared
controls, color palettes, responsive behavior, and accessibility across the shell,
chat, schedules, knowledge, settings, and global search. - Keep the existing local controls and tokens for this batch. Each surface lands as
its own reviewable change, with desktop/mobile screenshots and interaction evidence.
2. Agent contract for apps/
apps/AGENTS.md(with the repo'sCLAUDE.mdsymlink convention) as the lean correction
file for the TypeScript workspace — in the spirit of the root AGENTS.md, not a second copy
of the docs: the pnpm-workspace commands, the contracts → committedopenapi.json→
generated-client drift rule, the BFF security invariants (sealed HttpOnly cookies,
double-submit CSRF, same-origin check, rate limiting with trusted proxy hops, the
STUDIO_IMAGE=1/STUDIO_ALLOW_UNAUTHENTICATED=1refusals), and the standing
"published@stacklok-oss/mecatl-sdkonly, neversdk/typescript" rule.- A pointer to it from the root AGENTS.md (the root file stays lean).
- Skills under
.claude/skills/for the recurring Studio loops — e.g. add a surface
(contracts schema → BFF route → regenerate client → web feature → proofs) and touch Studio
configuration. Held to the same bar as the existing skills (to-acceptance-plan,
plan-orchestrate,test-writer). - Rules / markdown instructions for the conventions that are currently tribal: TanStack
file-route layout, feature-folder boundaries, "nofetchoutsidelib/api-client", the
Hono route + Zod schema + problem-details shape, and the Biome formatting contract. - Acceptance: an agent given "add surface X" follows the contract without reading the tree.
3. Cover the app with e2e and unit tests
- Browser e2e with Playwright, reusing the conventions already in the repo
(sdk/typescript/e2e/browser/playwright.config.ts) and theplaywright:resolver already
wired in.actrace.yml, so the proofs are citable from acceptance plans. - Journeys: unauthenticated → login → workspace; chat send → streamed run → mid-run controls;
capability-gated schedules empty state; knowledge inventory; settings; global search and the
shortcuts reference; connection-lost banner; a rejected CSRF mutation. - Unit/component gaps above the BFF suite. test(studio): integration suite over the real SDK against mecated --mock #1767 gives 7 integration tests over the real
SDK against a spawnedmecated --mock, and the bootstrap gives 26 server proofs — but only
3 web proofs (auth-gate,connection-status-banner,api-client). Bringapps/webto
real coverage with Vitest + Testing Library as the feature stacks land. - CI: a Playwright job (or an extension of the
studiojob) with cached browsers and
failure artifacts, offline by default (mock runtime, no live provider, no network). - Decide: is there an enforced coverage floor, or are named proofs per acceptance criterion
the only gate?
4. Rethink the app folder structure
- The bootstrap layout —
apps/{contracts,server,web}, with
web/src/{components/{shell,ui},features,lib,routes}— was sized for a skeleton. Five
feature stacks (Studio chat: sessions, streamed runs, controls, chat workspace #1747–Studio global search palette and keyboard-shortcuts reference #1751) land on top of it. - Questions to settle: feature-sliced vs layer-first in
apps/web; where domain hooks and
shared state live; whetherapps/contractsstays one package or splits schemas from the
generated client; whether the BFF'sroutes/+mecatl/+auth/split holds at five
surfaces; and whether the workspace staysapps/now that it holds exactly one app. - Deliverable: a short structure decision, then the move as one mechanical PR with no
behavior change, so the diff stays reviewable — done before the e2e work lands, so the
proofs are not written against paths that are about to move.
5. Look at all the configuration
apps/.env.exampleagainst the realMECATL_*(target) /STUDIO_*(Studio-owned) matrix:
every variable documented once, with default, required-ness, and the fail-closed behaviour
(e.g. RFC 9728 discovery whenMECATL_RESOURCE_URLis absent).apps/Dockerfile(Chainguard node pinned by digest),apps/docker/mecated.Dockerfile,
apps/docker-compose.yml,apps/.dockerignore: layer caching, non-root, healthcheck,
image-only refusals, and who refreshes the digest pin.apps/README.mdreconciled with theuser-docs/building/deployment/studio.mdpage (docs(user-docs): Mecatl Studio web UI deployment page #1765) —
one source of truth, not a drifting duplicate.apps/package.jsonscripts vsapps/Taskfile.ymlvs roottask studio:*: one entry point
per action, no third way to run the same thing.apps/biome.json,tsconfig.base.json,.node-version,.npmrc, the pnpm workspace and
lockfile policy; and a re-read of thestudioCI job and thepublish-studiorelease job
against whatever the four axes above change.
6. Release and deploy automation
- Every
v*release of mecak8s must produce and roll out the matching Studio UI. Today
publish-studioruns on the tag withneeds: guardonly — a sibling of the mecak8s image,
coupled to nothing, and deployed by nothing; themecak8schart does not know Studio exists. - Release train:
publish-studiojoins the ordered train the chart job already relies on
(needs: [guard, publish-mecak8s], "publish the chart only after its default image tag
exists"), signed and attested like its siblings. The SDK ordering is the risk to settle —
Studio builds against the published@stacklok-oss/mecatl-sdk. - Deploy surface: Studio Deployment + Service + Ingress in external mode against the in-cluster
mecak8s Service, off by default, with the image selected by the chart's existing
digest/tag/v<chart-version>convention so a chart release deploys the matching UI
with no values edit. - Version pins:
studio.image.tagjoins the release pin set (Chart.yamlversion/appVersion,
image.tag, thecut-releasebump list) so a chart can never ship a stale UI. - Rollout: GitOps auto-sync, a deploy workflow, or a release-opened values PR — the actual
"automatic deploy" decision; everything above only makes it possible.
Steps
Delivered as sub-issues. Ordering: contract and configuration first (cheap, unblocks everyone),
structure before tests (so proofs are not written against paths that are about to move),
release/deploy once there is a UI worth shipping. Design alignment is active as
its own stream under #1736.
- Studio agent contract: apps/AGENTS.md, skills, and web/server rules #1775 agent contract for
apps/—apps/AGENTS.md, skills, rules - Studio configuration sweep: env matrix, images, docs, entry points #1778 configuration sweep — env matrix, images, docs, entry points
- Studio app structure: layout decision and the mechanical move #1777 app structure — layout decision plus the mechanical move
- Studio test coverage: Playwright journeys, apps/web unit gaps, CI job #1776 test coverage — Playwright journeys,
apps/webunit gaps, CI job - Studio release and deploy automation: publish and roll out the UI with every mecak8s release #1780 release and deploy automation — Studio image and chart in the mecak8s release train
- Studio design review and parity tracking #1779 design review and parity (UX, UI, components, colors, CSS) —
active; implementation under Mecatl Studio: bring the web UI into the repository as apps/ and release its image #1736
#1776 supersedes the empty placeholders #1769, #1770, and #1771; #1778 subsumes or hands off
#1772 (README screenshots).
Delivery
Same acceptance-plan spine as #1736, classified per docs/development-process.md at plan time
rather than asserted here. Expected shape: the agent contract and the configuration sweep look
Routine/Cleanup (no behaviour, contract, or interface change); the folder rethink is Bounded
with a structure decision and a no-behaviour-change move; the e2e coverage is Bounded (new
named proofs, reusing the playwright: / vitest: ac-trace resolvers); design alignment is
Bounded per surface where it changes UI alone. #1845 may be Architectural because it
changes the public auth/status boundary;
the release and deploy automation is Architectural (it changes the release artifact set, the
published chart's contract, and the deployment surface).
Open questions and resolved design decisions
- Design sign-off is resolved: maintainers review desktop/mobile screenshots and the key interaction flow per surface; Studio design review and parity tracking #1779 records completion.
- Design primitives are resolved for this batch: keep local controls and tokens; no external UI-kit dependency.
- Playwright in the existing
studioCI job or its own? Enforced coverage floor or not? - Does the workspace stay
apps/, or becomestudio/? - Is Studio part of the
mecak8schart or its own chart, and what rolls the new version out —
GitOps auto-sync, a deploy workflow, or a values PR?
Activity