diff --git a/desktop/app.go b/desktop/app.go
index cd0101a1be..f4d2d34b60 100644
--- a/desktop/app.go
+++ b/desktop/app.go
@@ -6076,7 +6076,10 @@ type SkillView struct {
Model string `json:"model,omitempty"`
Effort string `json:"effort,omitempty"`
AllowedTools []string `json:"allowedTools,omitempty"`
- Color string `json:"color,omitempty"`
+ // ReadOnly mirrors frontmatter read-only; omitted/false keeps the legacy
+ // writable default for older profiles.
+ ReadOnly bool `json:"readOnly,omitempty"`
+ Color string `json:"color,omitempty"`
// Invocation is the user-facing slash name; InvocationMode preserves the
// frontmatter policy used by the subagent profile editor.
Invocation string `json:"invocation,omitempty"`
@@ -6456,6 +6459,7 @@ func (a *App) SkillsSettings() SkillsSettingsView {
Model: s.Model,
Effort: s.Effort,
AllowedTools: append([]string{}, s.AllowedTools...),
+ ReadOnly: s.ReadOnly,
Color: s.Color,
Invocation: "/" + s.SlashName(),
InvocationMode: s.Invocation,
diff --git a/desktop/frontend/src/__tests__/settings-refresh-snapshot.test.tsx b/desktop/frontend/src/__tests__/settings-refresh-snapshot.test.tsx
index 52b46fb930..9d1372dd95 100644
--- a/desktop/frontend/src/__tests__/settings-refresh-snapshot.test.tsx
+++ b/desktop/frontend/src/__tests__/settings-refresh-snapshot.test.tsx
@@ -78,7 +78,7 @@ function baseSettings(displayMode: "standard" | "compact" = "standard"): Setting
permissions: { mode: "ask", allow: [], ask: [], deny: [] },
sandbox: { bash: "enforce", network: false, workspaceRoot: "", allowWrite: [], effectiveWorkspaceRoot: "/work", effectiveWriteRoots: ["/work"], shell: "auto" },
network: { proxyMode: "auto", proxyUrl: "", noProxy: "", proxy: { type: "socks5", server: "", port: 0, username: "", password: "" } },
- agent: { temperature: 0, maxSteps: 0, plannerMaxSteps: 0, maxSubagentDepth: 2, systemPrompt: "", coldResumePrune: true, reasoningLanguage: "auto" },
+ agent: { temperature: 0, maxSteps: 0, plannerMaxSteps: 0, maxSubagentDepth: 2, maxSubagentConcurrency: 6, maxParallelWriters: 3, systemPrompt: "", coldResumePrune: true, reasoningLanguage: "auto" },
bot: {
enabled: false,
model: "",
diff --git a/desktop/frontend/src/components/SettingsPanel.tsx b/desktop/frontend/src/components/SettingsPanel.tsx
index 7a9e820452..d2f13401ff 100644
--- a/desktop/frontend/src/components/SettingsPanel.tsx
+++ b/desktop/frontend/src/components/SettingsPanel.tsx
@@ -1246,7 +1246,7 @@ function normalizeSettingsView(view: SettingsView | null | undefined): SettingsV
noProxy: "",
proxy: { type: "socks5", server: "", port: 0, username: "", password: "" },
};
- const agent = view.agent ?? { temperature: 0, maxSteps: 0, plannerMaxSteps: 0, maxSubagentDepth: 2, systemPrompt: "", coldResumePrune: true, reasoningLanguage: "auto" };
+ const agent = view.agent ?? { temperature: 0, maxSteps: 0, plannerMaxSteps: 0, maxSubagentDepth: 2, maxSubagentConcurrency: 6, maxParallelWriters: 3, systemPrompt: "", coldResumePrune: true, reasoningLanguage: "auto" };
agent.plannerMaxSteps = Number.isFinite(agent.plannerMaxSteps) ? Math.max(0, Math.trunc(agent.plannerMaxSteps)) : 0;
agent.maxSteps = Number.isFinite(agent.maxSteps) ? Math.max(0, Math.trunc(agent.maxSteps)) : 0;
agent.maxSubagentDepth = Number.isFinite(agent.maxSubagentDepth) && agent.maxSubagentDepth <= 1 ? 1 : 2;
@@ -3950,8 +3950,14 @@ function ModelsSection({ s, busy, apply, backgroundApply }: ModelsSectionProps)
: !providerIsConfigured(defaultProviderView)
? t("settings.modelNeedsKey", { provider: modelProviderLabel(defaultProvider, defaultProviderView, t) })
: "";
- const agent = s.agent ?? { temperature: 0, maxSteps: 0, plannerMaxSteps: 0, maxSubagentDepth: 2, systemPrompt: "", coldResumePrune: true, reasoningLanguage: "auto" };
+ const agent = s.agent ?? { temperature: 0, maxSteps: 0, plannerMaxSteps: 0, maxSubagentDepth: 2, maxSubagentConcurrency: 6, maxParallelWriters: 3, systemPrompt: "", coldResumePrune: true, reasoningLanguage: "auto" };
const subagentDepth = Number.isFinite(agent.maxSubagentDepth) && agent.maxSubagentDepth <= 1 ? 1 : 2;
+ const subagentConcurrency = Number.isFinite(agent.maxSubagentConcurrency) && agent.maxSubagentConcurrency > 0
+ ? Math.max(1, Math.min(32, Math.floor(agent.maxSubagentConcurrency)))
+ : 6;
+ const parallelWriters = Number.isFinite(agent.maxParallelWriters) && agent.maxParallelWriters > 0
+ ? Math.max(1, Math.min(subagentConcurrency, Math.floor(agent.maxParallelWriters)))
+ : Math.min(3, subagentConcurrency);
useEffect(() => {
if (subtab !== "usage") return;
@@ -4077,6 +4083,38 @@ function ModelsSection({ s, busy, apply, backgroundApply }: ModelsSectionProps)
+