diff --git a/console/index.html b/console/index.html
index 22acdf1..e1dada7 100644
--- a/console/index.html
+++ b/console/index.html
@@ -273,6 +273,19 @@
explicit auth error, not a silent drift.
+
+
+
+ — not set —
+
+
+
+ Local folder the New Fleet wizard mirrors each agent's generated
+ config.toml into (<folder>/<agent-name>/config.toml),
+ alongside the S3 copy it deploys from — this is what "view an
+ agent's config" reads from, no S3 round-trip.
+
+
diff --git a/console/src/main.ts b/console/src/main.ts
index 8875e51..7c108cc 100644
--- a/console/src/main.ts
+++ b/console/src/main.ts
@@ -174,6 +174,47 @@ const mcp = mcpEl ? createPane(mcpEl, () => flag("mcpio")) : null;
});
})();
+// Local "Config folder" (studio#128) — where the New Fleet wizard mirrors
+// each agent's generated config.toml (alongside the S3 copy it deploys
+// from) and where the "view an agent's config" screen reads from, no S3
+// round-trip. Persisted like the theme/log-level settings above
+// (localStorage), not Tauri's app-config-dir — this setting *points at*
+// other local files, storing it in the hidden config dir would just be an
+// extra layer of indirection for no reason.
+(function setupConfigFolder(): void {
+ const pathEl = document.getElementById("config-folder-path");
+ const pickBtn = document.getElementById("config-folder-pick");
+ if (!pathEl || !pickBtn) return;
+ const KEY = "oab-studio.configFolder";
+
+ const render = (): void => {
+ let saved: string | null = null;
+ try {
+ saved = localStorage.getItem(KEY);
+ } catch {
+ /* storage unavailable — falls through to the placeholder */
+ }
+ pathEl.textContent = saved || "— not set —";
+ };
+ render();
+
+ pickBtn.addEventListener("click", () => {
+ const invoke = tauriInvoke();
+ if (!invoke) return;
+ invoke("plugin:dialog|open", { options: { directory: true } })
+ .then((path) => {
+ if (!path) return;
+ try {
+ localStorage.setItem(KEY, path);
+ } catch {
+ /* storage unavailable — the choice still applies this session */
+ }
+ render();
+ })
+ .catch((e) => note("error", `config folder pick failed: ${errText(e)}`));
+ });
+})();
+
// Build stamp (injected by vite) — shown under the brand and logged on launch,
// so it's obvious which commit this build is.
const BUILD = `v${__APP_VERSION__} · ${__BUILD_SHA__}`;
diff --git a/console/src/styles.css b/console/src/styles.css
index ea74ab1..03ec2d3 100644
--- a/console/src/styles.css
+++ b/console/src/styles.css
@@ -1244,6 +1244,38 @@ button.act:disabled {
color: var(--muted);
}
+.config-folder {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ max-width: 420px;
+ margin-top: 20px;
+ padding-top: 16px;
+ border-top: 1px solid var(--border);
+}
+.config-folder > label {
+ font-size: 12px;
+ color: var(--muted);
+}
+.config-folder-row {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+.config-folder-path {
+ flex: 1;
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font-size: 12px;
+ color: var(--text);
+ padding: 6px 8px;
+ border: 1px solid var(--border);
+ border-radius: 6px;
+ background: var(--bg);
+}
+
/* Compose (agent-deployment ADR, slice 1): the deploy panel's bundle-preview
step (`deploy.ts`'s `#deploy-compose`) — the standalone authoring tab this
used to also style is gone, see compose.ts. */
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index 4d6d0e0..2eb2d58 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -55,6 +55,11 @@ tauri-plugin-updater = "2"
# commit rather than the floating `dev` branch for reproducibility.
fix-path-env = { git = "https://github.com/tauri-apps/fix-path-env-rs", rev = "c4c45d503ea115a839aae718d02f79e7c7f0f673" }
+# Native folder-picker dialog (studio#128) — lets the operator choose the
+# local "Config folder" the New Fleet wizard mirrors generated config.toml
+# files into, instead of a hidden hardcoded path.
+tauri-plugin-dialog = "2"
+
# Its own workspace so the desktop build stays out of the root workspace's
# `cargo build --workspace` (kept to the small crates + CI).
[workspace]
diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json
index 4a8d596..aacca3c 100644
--- a/src-tauri/capabilities/default.json
+++ b/src-tauri/capabilities/default.json
@@ -9,6 +9,7 @@
"core:default",
"shell:allow-stdin-write",
"shell:allow-kill",
+ "dialog:allow-open",
{
"identifier": "shell:allow-spawn",
"allow": [
diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs
index 62c03ca..94f5492 100644
--- a/src-tauri/src/lib.rs
+++ b/src-tauri/src/lib.rs
@@ -773,6 +773,7 @@ pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_updater::Builder::new().build())
+ .plugin(tauri_plugin_dialog::init())
.setup(|app| {
if cfg!(debug_assertions) {
app.handle().plugin(