feat: resolve vendor Stable/Beta image tags from GHCR (studio#128) - #131
Merged
Conversation
Adds a "Config folder" field to the Debug drawer's Config tab — a user-picked local directory (native folder picker via tauri-plugin-dialog) that later work will mirror each agent's generated config.toml into (<folder>/<agent-name>/config.toml, alongside the existing S3 upload provision_agent/provision_agent_k8s already do — unchanged) and that the "view an agent's config" screen (also studio#128, separate follow-up) will read from directly, no S3 round-trip. This slice is just the setting itself: plugin registration + capability grant (dialog:allow-open — the app's capabilities/default.json had no dialog permission at all before this) + picker UI, persisted like the existing theme/log-level settings (localStorage), not Tauri's hidden app-config-dir — this setting points at other local files, so storing it in the hidden config dir would just be an extra layer of indirection. Wiring the wizard/view-screen to actually use it lands with those pieces. Verification: npm run typecheck clean, npm test 106/106 passing, npm run build succeeds. Rust side (plugin registration, Cargo.toml) not locally compiled — same pre-existing limitation as every other Rust change this week; tauri-plugin-dialog's exact API (invoke command name "plugin:dialog|open", options shape, return type for directory+non-multiple mode) was checked against the plugin's actual TypeScript source before using it, not guessed. Ref #128.
…image tags from GHCR (studio#128) Item 7 of #128's runbook. Backs the New Fleet wizard's Vendor + Image tag fields — resolves a vendor name to real, currently-published ghcr.io/openabdev/openab image tags instead of the operator guessing a tag that might not exist. Initially thought this needed a GitHub auth mechanism Studio doesn't have (GitHub's Packages REST API requires a read:packages-scoped token even for public packages) — Brett pushed back that reading a public GHCR image shouldn't need auth, which was right: ghcr.io itself speaks the standard OCI Distribution API, not just GitHub's REST API, and a public package supports the same anonymous pull-token flow `docker pull` uses with no login (`GET /token?scope=repository:<repo>:pull`, verified live against openabdev/openab before writing any code). Switched to that. - oabctl: new `vendor_images` module. `pre-beta-<vendor>` (Beta, the hourly rolling build) and the newest openab GitHub release whose matching `<version>-<vendor>` image is confirmed to exist (Stable) — verified via a manifest HEAD request per candidate (existence check, no image bytes transferred), not a bulk tag-list scan (this repo has thousands of tags across multiple pages). A release tag existing doesn't guarantee a matching image was ever published (`build-images.yml` is a manual `workflow_dispatch`, disconnected from cutting a release), so Stable is verified against GHCR directly rather than inferred from the release list alone. GitHub's releases API also needed a name-based filter alongside `prerelease`: at least one real release (`openab-0.10.0-beta.3`) has `prerelease: false` despite its name. - studio-cp: thin `resolve_vendor_image_tags` wrapper. - oab-mcp: new `resolve_vendor_image_tags` tool. Never errors on a failed GHCR/GitHub call — leaves the corresponding field `None`, the console falls back to a plain editable text field either way (Brett already confirmed manual image tag entry stays available). - src-tauri: bridge command, same shape as the other read-only wizard pickers (list_k8s_contexts etc). Console wiring (actually using this in the Vendor select) lands with the rest of the wizard UI (#128's items 1/3/4/5), not this PR. Ref #128.
brettchien
added a commit
that referenced
this pull request
Aug 29, 2026
…write (studio#128) (#132) Replaces the Template/Overlay compose-library step (empty on every fresh install by design, blocking the whole deploy flow — the original #119 screenshot that started this) with the vendor + chat platform + ACP flow confirmed with Brett across #128's design thread. ## Console (items 1-5 of the runbook, shipped together — all fields live on the same new Step 2 screen) - Vendor <select>: Claude/codex/agy/cursor/kiro. "agy" is only the display label — the option value is "antigravity" (the GHCR image variant / Dockerfile.package build-target name resolve_vendor_image_tags expects). - Image tag: pre-filled from resolve_vendor_image_tags (#131) — Stable if GHCR confirms it exists, else Beta (pre-beta-<vendor>), else left for manual entry. Always editable — no lookup failure blocks the field. - API key (optional): captured, stored as a secret server-side; not yet wired into config.toml (documented gap from #129, unchanged here). - Chat platform (optional, default none — "use ACP directly"): Discord/Telegram/LINE, reveals the right token field(s) per platform. k8s deploys refuse a non-empty selection both client-side (clean validation message) and server-side (#129's existing refusal) — config.toml secret resolution needs AWS credentials a k8s pod doesn't have. - Enable ACP checkbox: default checked, forced off + disabled for vendor=agy (its bridge bypasses openab-gateway's /acp route entirely). - Agent name: pre-filled with a random Greek god name, shuffle button to re-roll, still freely editable. - No separate "Preview bundle" step anymore — fill in the fields, Deploy. ## Backend: acp_enabled made caller-controlled (was hardcoded true in #127) #127 hardcoded `acp_enabled: Some(true)` inside build_default_manifest / build_default_k8s_manifest with no way for a caller to turn it off — fine when nothing exposed a toggle, not fine once the wizard has an actual checkbox (needed for the agy case above). Both functions, and AgentWizardInput, now take `acp_enabled: bool` explicitly: - studio-cp: build_default_manifest/build_default_k8s_manifest gained an `acp_enabled: bool` param — only generates the ACP auth secret when true. provision_from_library[_k8s] (the older compose-library path, unrelated to this wizard) pass `true` at their call sites, preserving #127's original unconditional-on behavior there unchanged. - oab-mcp: deploy_provision_agent's schema gained `acp_enabled: boolean`, defaulting to true when the caller omits it (same default #127 had, now explicit and overridable instead of baked in). - src-tauri: bridge command threads the new param through. Ref #128.
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.
Summary
Item 7 of #128's runbook. Backs the New Fleet wizard's Vendor + Image tag fields — resolves a vendor name to real, currently-published
ghcr.io/openabdev/openabimage tags instead of the operator guessing a tag that might not exist.Was blocked, now isn't: initially thought this needed a GitHub auth mechanism Studio doesn't have anywhere (GitHub's Packages REST API requires a
read:packages-scoped token even for public packages). Brett pushed back that reading a public GHCR image shouldn't need auth — right:ghcr.iospeaks the standard OCI Distribution API, not just GitHub's REST API, and supports the same anonymous pull-token flowdocker pulluses with no login. Verified live before writing any code:Change
oabctl: newvendor_imagesmodule. "Beta" =pre-beta-<vendor>(the hourly rolling build). "Stable" = the newest openab GitHub release whose matching<version>-<vendor>image is confirmed to actually exist — verified via a manifestHEADrequest per candidate (cheap existence check, no image bytes transferred), not a bulk tag-list scan (this repo has thousands of tags across multiple pages, confirmed live). A release tag existing doesn't guarantee a matching image was ever published (build-images.ymlis a manualworkflow_dispatch, completely disconnected from cutting a release — confirmed by reading both workflows), so Stable is verified against GHCR directly, not inferred from the release list alone. Also needed a name-based filter alongside GitHub'sprereleaseflag: at least one real release (openab-0.10.0-beta.3) hasprerelease: falsedespite its name — the flag alone isn't reliable.studio-cp: thinresolve_vendor_image_tagswrapper.oab-mcp: newresolve_vendor_image_tagstool. Never errors on a failed GHCR/GitHub call — leaves the corresponding fieldnull, matching Brett's earlier confirmation that manual image tag entry stays available as a fallback either way. Tool-count test bumped 18→19.src-tauri: bridge command, same shape as the other read-only wizard pickers (list_k8s_contextsetc).Console wiring (actually using this in the Vendor select) lands with the rest of the wizard UI (#128's items 1/3/4/5), not this PR.
Verification
aws-sdk-ec2OOM limitation as every other Rust PR this week.openabdev/openabpackage before writing the Rust code, not assumed.reqwest(already a directoabctldependency, unchanged version/features) is the only dependency touched — no new crate added.build-testjob is the real gate for compilation; this PR has no k8s/AWS-provisioning-path changes sobundle-macosrisk is low, but it's still the real signal forsrc-tauri-adjacent correctness (none of this crate is on the src-tauri layer beyond the new bridge command, which mirrors an existing one closely).Ref #128.
🤖 Generated with Claude Code