+ {hasExternalConflict ? (
+
+
+ {t("agents:profileExternalChangeTitle")}
+
+ {t("agents:profileExternalChangeDescription")}
+
+
+
+ ) : null}
= {}): AgentProfile {
+ return {
+ id: "profile-1" as AgentProfile["id"],
+ name: "Default",
+ agentId: "agent-1",
+ agentDisplayName: "Agent",
+ model: "model-a",
+ allowIndexing: false,
+ autoApprove: false,
+ cliFlags: [],
+ cliPassthrough: false,
+ createdAt: BASE_UPDATED_AT,
+ updatedAt: BASE_UPDATED_AT,
+ ...overrides,
+ };
+}
+
+describe("sameEditableProfile", () => {
+ it("ignores timestamps and object key order", () => {
+ expect(
+ sameEditableProfile(
+ profile({ configOptions: { z: "2", a: "1" }, updatedAt: UPDATED_AT }),
+ profile({ configOptions: { a: "1", z: "2" }, updatedAt: UPDATED_AT }),
+ ),
+ ).toBe(true);
+ });
+});
+
+describe("reconcileAgentProfileSnapshot", () => {
+ it("adopts a newer update when the editor is clean", () => {
+ const previous = profile();
+ const incoming = profile({ name: "Assistant", updatedAt: UPDATED_AT });
+ const result = reconcileAgentProfileSnapshot({
+ previous,
+ incoming,
+ draft: previous,
+ saved: previous,
+ conflicted: false,
+ });
+
+ expect(result.kind).toBe("clean-adopted");
+ expect(result.draft.name).toBe("Assistant");
+ expect(result.conflicted).toBe(false);
+ });
+
+ it("preserves a dirty draft and records a recoverable conflict", () => {
+ const previous = profile();
+ const draft = profile({ name: "Local draft" });
+ const incoming = profile({ name: "Assistant", updatedAt: UPDATED_AT });
+ const result = reconcileAgentProfileSnapshot({
+ previous,
+ incoming,
+ draft,
+ saved: previous,
+ conflicted: false,
+ });
+
+ expect(result.kind).toBe("external-conflict");
+ expect(result.draft.name).toBe("Local draft");
+ expect(result.saved.name).toBe("Assistant");
+ expect(result.conflicted).toBe(true);
+ });
+
+ it("treats the matching submitted snapshot as its own acknowledgement", () => {
+ const previous = profile();
+ const submitted = profile({ name: "Submitted" });
+ const incoming = profile({ name: "Submitted", updatedAt: UPDATED_AT });
+ const result = reconcileAgentProfileSnapshot({
+ previous,
+ incoming,
+ draft: submitted,
+ saved: previous,
+ submitted,
+ conflicted: false,
+ });
+
+ expect(result.kind).toBe("own-acknowledgement");
+ expect(result.draft).toBe(incoming);
+ expect(result.conflicted).toBe(false);
+ });
+
+ it("keeps edits made after submission when the acknowledgement arrives", () => {
+ const previous = profile();
+ const submitted = profile({ name: "Submitted" });
+ const newerDraft = profile({ name: "Edited again" });
+ const incoming = profile({ name: "Submitted", updatedAt: UPDATED_AT });
+ const result = reconcileAgentProfileSnapshot({
+ previous,
+ incoming,
+ draft: newerDraft,
+ saved: previous,
+ submitted,
+ conflicted: false,
+ });
+
+ expect(result.kind).toBe("own-acknowledgement");
+ expect(result.draft.name).toBe("Edited again");
+ expect(result.saved.name).toBe("Submitted");
+ });
+
+ it("ignores a late response older than the current baseline", () => {
+ const previous = profile({ name: "Current", updatedAt: LATEST_UPDATED_AT });
+ const incoming = profile({ name: "Late", updatedAt: UPDATED_AT });
+ const result = reconcileAgentProfileSnapshot({
+ previous,
+ incoming,
+ draft: previous,
+ saved: previous,
+ conflicted: false,
+ });
+
+ expect(result.kind).toBe("ignored");
+ expect(result.saved.name).toBe("Current");
+ });
+});
+
+describe("reconcileAgentProfileSnapshot dynamic drafts", () => {
+ it("preserves a dynamic candidate draft during an external routing update", () => {
+ const candidate = {
+ position: 0,
+ executionProfileId: "profile-2" as AgentProfile["id"],
+ enabled: true,
+ policies: {
+ version: 1,
+ transient: {
+ retry: { enabled: false, maxRetries: 0, initialIntervalSeconds: 0 },
+ waitForReset: { enabled: false, maxWaitSeconds: 0 },
+ onExhausted: "skip" as const,
+ },
+ hard: {
+ retry: { enabled: false, maxRetries: 0, initialIntervalSeconds: 0 },
+ waitForReset: { enabled: false, maxWaitSeconds: 0 },
+ onExhausted: "skip" as const,
+ },
+ },
+ };
+ const previous = profile({ kind: "dynamic", dynamic: { version: 1, candidates: [] } });
+ const draft = profile({ kind: "dynamic", dynamic: { version: 1, candidates: [candidate] } });
+ const incoming = profile({
+ kind: "dynamic",
+ dynamic: { version: 2, candidates: [] },
+ updatedAt: UPDATED_AT,
+ });
+
+ const result = reconcileAgentProfileSnapshot({
+ previous,
+ incoming,
+ draft,
+ saved: previous,
+ conflicted: false,
+ });
+
+ expect(result.kind).toBe("external-conflict");
+ expect(result.draft.dynamic?.candidates).toHaveLength(1);
+ expect(result.saved.dynamic?.version).toBe(2);
+ });
+});
diff --git a/apps/web/components/settings/agent-profile-reconciliation.ts b/apps/web/components/settings/agent-profile-reconciliation.ts
new file mode 100644
index 0000000000..9fc76581f7
--- /dev/null
+++ b/apps/web/components/settings/agent-profile-reconciliation.ts
@@ -0,0 +1,108 @@
+import { compareTimestamps } from "@/lib/state/slices/settings/types";
+import type { AgentProfile } from "@/lib/types/agent-profile";
+
+const EDITABLE_FIELDS = [
+ "name",
+ "model",
+ "fallbackModel",
+ "autoFallback",
+ "mode",
+ "configOptions",
+ "allowIndexing",
+ "autoApprove",
+ "cliFlags",
+ "commandPrefix",
+ "envVars",
+ "cliPassthrough",
+ "enabled",
+ "dynamic",
+] as const satisfies readonly (keyof AgentProfile)[];
+
+type EditableProfile = Pick;
+
+function canonicalize(value: unknown): unknown {
+ if (Array.isArray(value)) return value.map(canonicalize);
+ if (!value || typeof value !== "object") return value;
+ return Object.fromEntries(
+ Object.entries(value as Record)
+ .sort(([left], [right]) => left.localeCompare(right))
+ .map(([key, entry]) => [key, canonicalize(entry)]),
+ );
+}
+
+function editableSnapshot(profile: AgentProfile): EditableProfile {
+ return Object.fromEntries(
+ EDITABLE_FIELDS.map((field) => [field, profile[field]]),
+ ) as EditableProfile;
+}
+
+export function sameEditableProfile(left: AgentProfile, right: AgentProfile): boolean {
+ return (
+ JSON.stringify(canonicalize(editableSnapshot(left))) ===
+ JSON.stringify(canonicalize(editableSnapshot(right)))
+ );
+}
+
+function incomingIsNewer(incoming: AgentProfile, baseline: AgentProfile): boolean {
+ const timestampOrder = compareTimestamps(incoming.updatedAt, baseline.updatedAt);
+ if (timestampOrder !== 0) return timestampOrder > 0;
+ return !sameEditableProfile(incoming, baseline);
+}
+
+export type ProfileReconciliationInput = {
+ previous: AgentProfile;
+ incoming: AgentProfile;
+ draft: AgentProfile;
+ saved: AgentProfile;
+ submitted?: AgentProfile | null;
+ conflicted: boolean;
+};
+
+export type ProfileReconciliationResult = {
+ draft: AgentProfile;
+ saved: AgentProfile;
+ conflicted: boolean;
+ kind: "ignored" | "own-acknowledgement" | "clean-adopted" | "external-conflict";
+};
+
+/**
+ * Reconciles one authoritative profile snapshot with an open local editor.
+ * The helper never merges competing field values: a dirty draft remains local
+ * and the newest saved snapshot becomes the baseline for explicit recovery.
+ */
+export function reconcileAgentProfileSnapshot({
+ previous,
+ incoming,
+ draft,
+ saved,
+ submitted,
+ conflicted,
+}: ProfileReconciliationInput): ProfileReconciliationResult {
+ if (incoming.id !== previous.id || incoming.id !== saved.id) {
+ return { draft, saved, conflicted, kind: "ignored" };
+ }
+
+ const ownAcknowledgement = Boolean(submitted && sameEditableProfile(incoming, submitted));
+ if (!incomingIsNewer(incoming, saved)) {
+ return { draft, saved, conflicted, kind: "ignored" };
+ }
+
+ if (ownAcknowledgement) {
+ return {
+ draft: sameEditableProfile(draft, submitted!) ? incoming : draft,
+ saved: incoming,
+ conflicted,
+ kind: "own-acknowledgement",
+ };
+ }
+
+ if (sameEditableProfile(draft, saved)) {
+ return { draft: incoming, saved: incoming, conflicted, kind: "clean-adopted" };
+ }
+
+ return { draft, saved: incoming, conflicted: true, kind: "external-conflict" };
+}
+
+export function isProfileRevisionNewer(incoming: AgentProfile, baseline: AgentProfile): boolean {
+ return incomingIsNewer(incoming, baseline);
+}
diff --git a/apps/web/components/settings/dynamic-agent-profile-editor-draft.ts b/apps/web/components/settings/dynamic-agent-profile-editor-draft.ts
index 5b7e0e0b5a..9caa2946a2 100644
--- a/apps/web/components/settings/dynamic-agent-profile-editor-draft.ts
+++ b/apps/web/components/settings/dynamic-agent-profile-editor-draft.ts
@@ -1,6 +1,6 @@
"use client";
-import { useState } from "react";
+import { useCallback, useEffect, useRef, useState } from "react";
import { agentProfileId as toAgentProfileId } from "@/lib/types/ids";
import type { AgentProfile } from "@/lib/types/http";
import type {
@@ -9,6 +9,11 @@ import type {
DynamicErrorClass,
DynamicErrorPolicy,
} from "@/lib/types/agent-profile";
+import {
+ isProfileRevisionNewer,
+ reconcileAgentProfileSnapshot,
+ sameEditableProfile,
+} from "@/components/settings/agent-profile-reconciliation";
type DynamicAgentProfileEditorDraftProps = {
profile: AgentProfile;
@@ -20,6 +25,9 @@ export type DynamicAgentProfileEditorDraft = {
candidates: DynamicAgentCandidate[];
profileEnabled: boolean;
dynamicVersion: number;
+ currentProfile: AgentProfile;
+ savedProfile: AgentProfile;
+ hasExternalConflict: boolean;
updateName: (name: string) => void;
updateProfileEnabled: (enabled: boolean) => void;
addCandidate: (executionProfileId: string) => void;
@@ -32,6 +40,8 @@ export type DynamicAgentProfileEditorDraft = {
patch: Partial,
) => void;
applyProfile: (profile: AgentProfile) => void;
+ markProfileSubmitted: (profile: AgentProfile | null) => void;
+ acceptProfileSaveResponse: (profile: AgentProfile, submitted: AgentProfile) => void;
reset: () => void;
};
@@ -66,8 +76,22 @@ export function useDynamicAgentProfileEditorDraft({
);
const [profileEnabled, setProfileEnabled] = useState(profile.enabled !== false);
const [dynamicVersion, setDynamicVersion] = useState(profile.dynamic?.version ?? 1);
+ const [savedProfile, setSavedProfile] = useState(profile);
+ const [hasExternalConflict, setHasExternalConflict] = useState(false);
+ const previousProfileRef = useRef(profile);
+ const submittedProfileRef = useRef(null);
+ const savedProfileRef = useRef(savedProfile);
+ const currentProfileRef = useRef(profile);
+
+ const currentProfile = {
+ ...profile,
+ name,
+ enabled: profileEnabled,
+ dynamic: { version: dynamicVersion, candidates },
+ };
+ savedProfileRef.current = savedProfile;
+ currentProfileRef.current = currentProfile;
- const initialCandidates = profile.dynamic?.candidates ?? [];
const notifyDraft = (
nextName: string,
nextCandidates: DynamicAgentCandidate[],
@@ -161,24 +185,74 @@ export function useDynamicAgentProfileEditorDraft({
};
const reset = () => {
- setName(profile.name);
- setProfileEnabled(profile.enabled !== false);
- setCandidates(initialCandidates);
- setDynamicVersion(profile.dynamic?.version ?? 1);
- };
-
- const applyProfile = (nextProfile: AgentProfile) => {
+ const nextProfile = savedProfileRef.current;
setName(nextProfile.name);
setProfileEnabled(nextProfile.enabled !== false);
setCandidates(nextProfile.dynamic?.candidates ?? []);
setDynamicVersion(nextProfile.dynamic?.version ?? 1);
+ setHasExternalConflict(false);
+ submittedProfileRef.current = null;
};
+ const applyProfile = useCallback((nextProfile: AgentProfile) => {
+ setName(nextProfile.name);
+ setProfileEnabled(nextProfile.enabled !== false);
+ setCandidates(nextProfile.dynamic?.candidates ?? []);
+ setDynamicVersion(nextProfile.dynamic?.version ?? 1);
+ }, []);
+
+ const markProfileSubmitted = useCallback((submitted: AgentProfile | null) => {
+ submittedProfileRef.current = submitted;
+ }, []);
+
+ const acceptProfileSaveResponse = useCallback(
+ (nextProfile: AgentProfile, submitted: AgentProfile) => {
+ if (!isProfileRevisionNewer(nextProfile, savedProfileRef.current)) {
+ submittedProfileRef.current = null;
+ return;
+ }
+ setSavedProfile(nextProfile);
+ if (sameEditableProfile(currentProfileRef.current, submitted)) applyProfile(nextProfile);
+ setHasExternalConflict(false);
+ submittedProfileRef.current = null;
+ },
+ [applyProfile],
+ );
+
+ useEffect(() => {
+ const previous = previousProfileRef.current;
+ previousProfileRef.current = profile;
+ if (profile.id !== previous.id) {
+ submittedProfileRef.current = null;
+ setSavedProfile(profile);
+ applyProfile(profile);
+ setHasExternalConflict(false);
+ return;
+ }
+
+ const result = reconcileAgentProfileSnapshot({
+ previous,
+ incoming: profile,
+ draft: currentProfileRef.current,
+ saved: savedProfileRef.current,
+ submitted: submittedProfileRef.current,
+ conflicted: hasExternalConflict,
+ });
+ if (result.kind === "ignored") return;
+ setSavedProfile(result.saved);
+ if (!sameEditableProfile(result.draft, currentProfileRef.current)) applyProfile(result.draft);
+ setHasExternalConflict(result.conflicted);
+ if (result.kind === "own-acknowledgement") submittedProfileRef.current = null;
+ }, [applyProfile, hasExternalConflict, profile]);
+
return {
name,
candidates,
profileEnabled,
dynamicVersion,
+ currentProfile,
+ savedProfile,
+ hasExternalConflict,
updateName,
updateProfileEnabled,
addCandidate,
@@ -187,6 +261,8 @@ export function useDynamicAgentProfileEditorDraft({
updateCandidate,
updateCandidatePolicy,
applyProfile,
+ markProfileSubmitted,
+ acceptProfileSaveResponse,
reset,
};
}
diff --git a/apps/web/components/settings/dynamic-agent-profile-editor-state.ts b/apps/web/components/settings/dynamic-agent-profile-editor-state.ts
index a5ea3ac4a5..36d3f169e9 100644
--- a/apps/web/components/settings/dynamic-agent-profile-editor-state.ts
+++ b/apps/web/components/settings/dynamic-agent-profile-editor-state.ts
@@ -31,6 +31,7 @@ export type DynamicAgentProfileEditorState = {
name: string;
profileEnabled: boolean;
standalone: boolean;
+ hasExternalConflict: boolean;
routingEnabled: boolean;
enabledLabel: string;
concreteProfiles: AgentProfile[];
@@ -47,6 +48,7 @@ export type DynamicAgentProfileEditorState = {
patch: Partial,
) => void;
candidates: DynamicAgentCandidate[];
+ discardDraft: () => void;
};
function dynamicProfilePayload(
@@ -110,13 +112,6 @@ export function useDynamicAgentProfileEditorState({
const setSettingsAgents = useAppStore((state) => state.setSettingsAgents);
const setAgentProfiles = useAppStore((state) => state.setAgentProfiles);
const draft = useDynamicAgentProfileEditorDraft({ profile, onDraftChange });
- const [savedRevision, setSavedRevision] = useState(
- dynamicDraftRevision(
- profile.name,
- profile.dynamic?.candidates ?? [],
- profile.enabled !== false,
- ),
- );
const [saving, setSaving] = useState(false);
const standalone = onDraftChange === undefined;
@@ -154,11 +149,14 @@ export function useDynamicAgentProfileEditorState({
!routingEnabled ||
!draft.name.trim() ||
draft.candidates.length === 0 ||
- !profile.dynamic
+ !profile.dynamic ||
+ draft.hasExternalConflict
) {
return;
}
setSaving(true);
+ const submitted = draft.currentProfile;
+ draft.markProfileSubmitted(submitted);
try {
const draftPayload = {
name: draft.name.trim(),
@@ -195,16 +193,10 @@ export function useDynamicAgentProfileEditorState({
item.profiles.map((itemProfile) => toAgentProfileOption(item, itemProfile)),
),
);
- draft.applyProfile(updated);
- setSavedRevision(
- dynamicDraftRevision(
- updated.name,
- updated.dynamic?.candidates ?? draft.candidates,
- updated.enabled !== false,
- ),
- );
+ draft.acceptProfileSaveResponse(updated, submitted);
toast({ title: t("agents:dynamicProfileSaved") });
} catch (error) {
+ draft.markProfileSubmitted(null);
if (isHandledApiError(error)) return;
toast({
title: t("agents:failedToSaveProfile"),
@@ -217,6 +209,11 @@ export function useDynamicAgentProfileEditorState({
};
const draftRevision = dynamicDraftRevision(draft.name, draft.candidates, draft.profileEnabled);
+ const savedRevision = dynamicDraftRevision(
+ draft.savedProfile.name,
+ draft.savedProfile.dynamic?.candidates ?? [],
+ draft.savedProfile.enabled !== false,
+ );
const policiesValid = draft.candidates.every(
(candidate) =>
isDynamicErrorPolicyValid(candidate.policies.transient) &&
@@ -225,6 +222,8 @@ export function useDynamicAgentProfileEditorState({
let invalidReason = t("agents:dynamicPolicyValidation");
if (!draft.name.trim()) invalidReason = t("agents:profileNameRequired");
else if (draft.candidates.length === 0) invalidReason = t("agents:noDynamicCandidates");
+ else if (draft.hasExternalConflict)
+ invalidReason = t("agents:profileExternalChangeInvalidReason");
useSettingsSaveContributor({
id: `dynamic-profile:${profile.id}`,
revision: draftRevision,
@@ -232,6 +231,7 @@ export function useDynamicAgentProfileEditorState({
canSave:
routingEnabled &&
!saving &&
+ !draft.hasExternalConflict &&
Boolean(draft.name.trim()) &&
draft.candidates.length > 0 &&
policiesValid,
@@ -240,13 +240,6 @@ export function useDynamicAgentProfileEditorState({
discard: () => {
if (!standalone) return;
draft.reset();
- setSavedRevision(
- dynamicDraftRevision(
- profile.name,
- profile.dynamic?.candidates ?? [],
- profile.enabled !== false,
- ),
- );
},
});
@@ -254,6 +247,7 @@ export function useDynamicAgentProfileEditorState({
name: draft.name,
profileEnabled: draft.profileEnabled,
standalone,
+ hasExternalConflict: draft.hasExternalConflict,
routingEnabled,
enabledLabel,
concreteProfiles,
@@ -266,5 +260,6 @@ export function useDynamicAgentProfileEditorState({
updateCandidate: draft.updateCandidate,
updateCandidatePolicy: draft.updateCandidatePolicy,
candidates: draft.candidates,
+ discardDraft: draft.reset,
};
}
diff --git a/apps/web/components/settings/dynamic-agent-profile-editor.tsx b/apps/web/components/settings/dynamic-agent-profile-editor.tsx
index c147a22a4b..d62c67c059 100644
--- a/apps/web/components/settings/dynamic-agent-profile-editor.tsx
+++ b/apps/web/components/settings/dynamic-agent-profile-editor.tsx
@@ -1,7 +1,9 @@
"use client";
import { useTranslation } from "react-i18next";
-import { IconInfoCircle } from "@tabler/icons-react";
+import { IconAlertTriangle, IconInfoCircle } from "@tabler/icons-react";
+import { Alert, AlertDescription, AlertTitle } from "@kandev/ui/alert";
+import { Button } from "@kandev/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@kandev/ui/card";
import { Separator } from "@kandev/ui/separator";
import { Switch } from "@kandev/ui/switch";
@@ -136,6 +138,24 @@ export function DynamicAgentProfileEditor({
onEnabledChange={state.updateProfileEnabled}
/>
)}
+ {state.hasExternalConflict ? (
+
+
+ {t("agents:profileExternalChangeTitle")}
+
+ {t("agents:profileExternalChangeDescription")}
+
+
+
+ ) : null}
{state.standalone ? (
diff --git a/apps/web/e2e/tests/settings/mobile-settings-agent-configuration.spec.ts b/apps/web/e2e/tests/settings/mobile-settings-agent-configuration.spec.ts
new file mode 100644
index 0000000000..cea2ee346a
--- /dev/null
+++ b/apps/web/e2e/tests/settings/mobile-settings-agent-configuration.spec.ts
@@ -0,0 +1,33 @@
+import { test, expect } from "../../fixtures/test-base";
+import {
+ expandSettingsToolCalls,
+ startSettingsSession,
+ waitForSettingsSession,
+} from "./settings-agent-configuration-helpers";
+
+test.describe("Mobile agent-accessible settings", () => {
+ test("keeps the compact settings flow visible on a phone viewport", async ({
+ testPage,
+ apiClient,
+ seedData,
+ }) => {
+ await testPage.setViewportSize({ width: 390, height: 844 });
+ const originalProfile = await apiClient.getAgentProfile(seedData.agentProfileId);
+ try {
+ const session = await startSettingsSession(apiClient, seedData);
+ const page = await waitForSettingsSession(testPage, apiClient, session.task_id);
+
+ await expandSettingsToolCalls(page);
+ await expect(page.chat.getByText("Kandev: Search Settings")).toBeVisible();
+ await expect(page.chat.getByText("Kandev: Describe Setting")).toBeVisible();
+ await expect(page.chat.getByText("Kandev: List Settings Resources")).toBeVisible();
+ await expect(page.chat.getByText("Kandev: Get Settings")).toBeVisible();
+ await expect(page.chat.getByText("Kandev: Update Settings")).toBeVisible();
+ expect(await testPage.evaluate(() => document.documentElement.scrollWidth)).toBe(
+ await testPage.evaluate(() => document.documentElement.clientWidth),
+ );
+ } finally {
+ await apiClient.updateAgentProfile(seedData.agentProfileId, { name: originalProfile.name });
+ }
+ });
+});
diff --git a/apps/web/e2e/tests/settings/settings-agent-configuration-helpers.ts b/apps/web/e2e/tests/settings/settings-agent-configuration-helpers.ts
new file mode 100644
index 0000000000..0f2d87f32a
--- /dev/null
+++ b/apps/web/e2e/tests/settings/settings-agent-configuration-helpers.ts
@@ -0,0 +1,46 @@
+import { expect, type Page } from "@playwright/test";
+import type { ApiClient } from "../../helpers/api-client";
+import { waitForLatestSessionDone } from "../../helpers/session";
+import type { SeedData } from "../../fixtures/test-base";
+import { SessionPage } from "../../pages/session-page";
+
+export function startSettingsSession(apiClient: ApiClient, seedData: SeedData) {
+ return apiClient.startConfigChat(
+ seedData.workspaceId,
+ seedData.agentProfileId,
+ [
+ 'e2e:message("Settings flow started")',
+ 'e2e:mcp:kandev:search_settings_kandev({"query":"terminal font size","limit":10})',
+ 'e2e:mcp:kandev:describe_setting_kandev({"key":"user_settings.terminal_font_size","operation":"update"})',
+ `e2e:mcp:kandev:list_settings_resources_kandev({"resource_type":"workflow","workspace_id":"${seedData.workspaceId}","limit":10})`,
+ `e2e:mcp:kandev:get_settings_kandev({"target":{"resource_type":"agent_profile","resource_id":"${seedData.agentProfileId}"},"keys":["name","model"]})`,
+ `e2e:mcp:kandev:update_settings_kandev({"target":{"resource_type":"agent_profile","resource_id":"${seedData.agentProfileId}"},"changes":{"name":"Agent settings E2E"}})`,
+ 'e2e:message("Settings flow complete")',
+ ].join("\n"),
+ );
+}
+
+export async function waitForSettingsSession(testPage: Page, apiClient: ApiClient, taskId: string) {
+ await waitForLatestSessionDone(
+ apiClient,
+ taskId,
+ 1,
+ "settings MCP session should complete before reading the result",
+ 30_000,
+ );
+ await testPage.goto(`/t/${taskId}`);
+ const page = new SessionPage(testPage);
+ await page.waitForLoad();
+ await page.waitForChatIdle({ timeout: 30_000 });
+ await expect(page.activeChat().getByText("Settings flow complete", { exact: true })).toBeVisible({
+ timeout: 60_000,
+ });
+ return page;
+}
+
+export async function expandSettingsToolCalls(page: SessionPage) {
+ const headers = page.chat.getByRole("button", { name: /\d+ tool calls?$/ });
+ for (let index = 0; index < (await headers.count()); index++) {
+ await headers.nth(index).click();
+ }
+}
diff --git a/apps/web/e2e/tests/settings/settings-agent-configuration.spec.ts b/apps/web/e2e/tests/settings/settings-agent-configuration.spec.ts
new file mode 100644
index 0000000000..f7c4ccbfe2
--- /dev/null
+++ b/apps/web/e2e/tests/settings/settings-agent-configuration.spec.ts
@@ -0,0 +1,32 @@
+import { test, expect } from "../../fixtures/test-base";
+import {
+ expandSettingsToolCalls,
+ startSettingsSession,
+ waitForSettingsSession,
+} from "./settings-agent-configuration-helpers";
+
+test.describe("Agent-accessible settings", () => {
+ test("searches and describes settings through the real MCP transport", async ({
+ testPage,
+ apiClient,
+ seedData,
+ }) => {
+ const originalProfile = await apiClient.getAgentProfile(seedData.agentProfileId);
+ try {
+ const session = await startSettingsSession(apiClient, seedData);
+ const page = await waitForSettingsSession(testPage, apiClient, session.task_id);
+
+ await expandSettingsToolCalls(page);
+ await expect(page.chat.getByText("Kandev: Search Settings")).toBeVisible();
+ await expect(page.chat.getByText("Kandev: Describe Setting")).toBeVisible();
+ await expect(page.chat.getByText("Kandev: List Settings Resources")).toBeVisible();
+ await expect(page.chat.getByText("Kandev: Get Settings")).toBeVisible();
+ await expect(page.chat.getByText("Kandev: Update Settings")).toBeVisible();
+ await expect((await apiClient.getAgentProfile(seedData.agentProfileId)).name).toBe(
+ "Agent settings E2E",
+ );
+ } finally {
+ await apiClient.updateAgentProfile(seedData.agentProfileId, { name: originalProfile.name });
+ }
+ });
+});
diff --git a/apps/web/lib/settings-discovery/contract.generated.json b/apps/web/lib/settings-discovery/contract.generated.json
new file mode 100644
index 0000000000..2f1ee8f8c8
--- /dev/null
+++ b/apps/web/lib/settings-discovery/contract.generated.json
@@ -0,0 +1,6186 @@
+{
+ "schema_version": "settings-catalog.v1",
+ "generated_by": "cmd/settings-catalog",
+ "domains": [
+ {
+ "domain": "agents",
+ "resource_type": "agent",
+ "label": "Agent definitions",
+ "description": "Saved agent definition metadata and MCP connection settings.",
+ "owner": "agent-settings",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "agent.name",
+ "field_path": "name",
+ "label": "Name",
+ "description": "Stable agent definition name.",
+ "json_type": "string",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "agent-settings"
+ },
+ {
+ "key": "agent.workspace_id",
+ "field_path": "workspace_id",
+ "label": "Workspace",
+ "description": "Owning workspace, when the definition is workspace-scoped.",
+ "json_type": "string",
+ "nullable": true,
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "agent-settings"
+ },
+ {
+ "key": "agent.supports_mcp",
+ "field_path": "supports_mcp",
+ "label": "Supports MCP",
+ "description": "Whether the agent definition supports MCP configuration.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.agent",
+ "authority": "org.config.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "agent.mcp_config_path",
+ "field_path": "mcp_config_path",
+ "label": "MCP configuration path",
+ "description": "Path used by the agent definition for MCP configuration.",
+ "json_type": "string",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.agent",
+ "authority": "org.config.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "agent.tui_config",
+ "field_path": "tui_config",
+ "label": "TUI definition",
+ "description": "Custom TUI definition owned by the explicit agent lifecycle surface.",
+ "json_type": "object",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "agent-settings"
+ },
+ {
+ "key": "agent.profiles",
+ "field_path": "profiles",
+ "label": "Profiles",
+ "description": "Profiles attached to this agent definition.",
+ "json_type": "array",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "agent-settings"
+ },
+ {
+ "key": "agent.capability_status",
+ "field_path": "capability_status",
+ "label": "Capability status",
+ "description": "Computed host capability status.",
+ "json_type": "string",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "agent-settings"
+ },
+ {
+ "key": "agent.capability_error",
+ "field_path": "capability_error",
+ "label": "Capability error",
+ "description": "Computed host capability diagnostic.",
+ "json_type": "string",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "agent-settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "agent-settings.agent.update",
+ "authority": "org.config.manage"
+ }
+ ],
+ "settings_href": "/settings/agents"
+ },
+ {
+ "domain": "profiles",
+ "resource_type": "agent_profile",
+ "label": "Agent profiles",
+ "description": "Saved agent profile settings used for future sessions.",
+ "owner": "agent-settings",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "agent_profile.name",
+ "field_path": "name",
+ "label": "name",
+ "description": "Profile display name.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.model",
+ "field_path": "model",
+ "label": "model",
+ "description": "Preferred model; empty uses the agent default.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.fallback_model",
+ "field_path": "fallback_model",
+ "label": "fallback_model",
+ "description": "Optional fallback model.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.auto_fallback",
+ "field_path": "auto_fallback",
+ "label": "auto_fallback",
+ "description": "Enable automatic fallback behavior.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.mode",
+ "field_path": "mode",
+ "label": "mode",
+ "description": "Agent operating mode.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.config_options",
+ "field_path": "config_options",
+ "label": "config_options",
+ "description": "Typed provider configuration options.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "replacement": true,
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.allow_indexing",
+ "field_path": "allow_indexing",
+ "label": "allow_indexing",
+ "description": "Legacy indexing permission field.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.auto_approve",
+ "field_path": "auto_approve",
+ "label": "auto_approve",
+ "description": "Automatically approve agent permissions.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.cli_passthrough",
+ "field_path": "cli_passthrough",
+ "label": "cli_passthrough",
+ "description": "Allow CLI passthrough mode.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.enabled",
+ "field_path": "enabled",
+ "label": "enabled",
+ "description": "Allow this profile for new work.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.cli_flags",
+ "field_path": "cli_flags",
+ "label": "cli_flags",
+ "description": "Complete replacement list of CLI flags.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "replacement": true,
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.env_vars",
+ "field_path": "env_vars",
+ "label": "env_vars",
+ "description": "Complete replacement list of environment variables.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "sensitive": true,
+ "replacement": true,
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.command_prefix",
+ "field_path": "command_prefix",
+ "label": "command_prefix",
+ "description": "Optional launcher command prefix.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.dynamic",
+ "field_path": "dynamic",
+ "label": "dynamic",
+ "description": "Versioned dynamic routing document.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "replacement": true,
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "agent-settings.profile.update",
+ "authority": "org.config.manage"
+ }
+ ],
+ "settings_href": "/settings/agents"
+ },
+ {
+ "domain": "profiles",
+ "resource_type": "agent_profile_mcp",
+ "label": "Profile MCP documents",
+ "description": "Separate MCP server settings for a saved agent profile.",
+ "owner": "agent-settings",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true
+ },
+ "fields": [
+ {
+ "key": "agent_profile_mcp.enabled",
+ "field_path": "enabled",
+ "label": "MCP enabled",
+ "description": "Enable the profile MCP document.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile-mcp",
+ "authority": "org.config.manage"
+ },
+ {
+ "key": "agent_profile_mcp.servers",
+ "field_path": "servers",
+ "label": "MCP servers",
+ "description": "Complete replacement map of validated MCP servers.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile-mcp",
+ "authority": "org.config.manage",
+ "sensitive": true,
+ "replacement": true
+ },
+ {
+ "key": "agent_profile_mcp.meta",
+ "field_path": "meta",
+ "label": "MCP metadata",
+ "description": "Preserved metadata from the MCP document.",
+ "json_type": "object",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "agent-settings",
+ "sensitive": true
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "agent-settings.profile-mcp.update",
+ "authority": "org.config.manage"
+ }
+ ],
+ "settings_href": "/settings/agents"
+ },
+ {
+ "domain": "automations",
+ "resource_type": "automation",
+ "label": "Workspace automations",
+ "description": "Workspace automation definitions.",
+ "owner": "automations",
+ "scope": "workspace",
+ "target": {
+ "scope": "workspace",
+ "requires_resource_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "automation.name",
+ "field_path": "name",
+ "label": "Name",
+ "description": "Automation name.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "automations",
+ "writable": true,
+ "validator": "automations.automation",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "automation.description",
+ "field_path": "description",
+ "label": "Description",
+ "description": "Automation description.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "automations",
+ "writable": true,
+ "validator": "automations.automation",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "automation.workflow_id",
+ "field_path": "workflow_id",
+ "label": "Workflow",
+ "description": "Workflow binding.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "automations",
+ "writable": true,
+ "validator": "automations.automation",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "automation.workflow_step_id",
+ "field_path": "workflow_step_id",
+ "label": "Workflow step",
+ "description": "Workflow step binding.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "automations",
+ "writable": true,
+ "validator": "automations.automation",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "automation.agent_profile_id",
+ "field_path": "agent_profile_id",
+ "label": "Agent profile",
+ "description": "Agent profile binding.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "automations",
+ "writable": true,
+ "validator": "automations.automation",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "automation.executor_profile_id",
+ "field_path": "executor_profile_id",
+ "label": "Executor profile",
+ "description": "Executor profile binding.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "automations",
+ "writable": true,
+ "validator": "automations.automation",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "automation.repositories",
+ "field_path": "repositories",
+ "label": "Repositories",
+ "description": "Repository and base-branch selection.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "automations",
+ "writable": true,
+ "validator": "automations.automation",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "automation.prompt",
+ "field_path": "prompt",
+ "label": "Prompt",
+ "description": "Automation prompt template.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "automations",
+ "writable": true,
+ "validator": "automations.automation",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "automation.task_title_template",
+ "field_path": "task_title_template",
+ "label": "Task title template",
+ "description": "Generated task title template.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "automations",
+ "writable": true,
+ "validator": "automations.automation",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "automation.enabled",
+ "field_path": "enabled",
+ "label": "Enabled",
+ "description": "Whether the automation is active.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "automations",
+ "writable": true,
+ "validator": "automations.automation",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "automation.max_concurrent_runs",
+ "field_path": "max_concurrent_runs",
+ "label": "Concurrent runs",
+ "description": "Maximum simultaneous runs.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "automations",
+ "writable": true,
+ "validator": "automations.automation",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "automation.continuation_policy",
+ "field_path": "continuation_policy",
+ "label": "Continuation policy",
+ "description": "How automation runs reuse tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "automations",
+ "writable": true,
+ "validator": "automations.automation",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "automation.task_mode",
+ "field_path": "task_mode",
+ "label": "Task mode",
+ "description": "Whether runs create visible tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "automations",
+ "writable": true,
+ "validator": "automations.automation",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "automation.repository_mode",
+ "field_path": "repository_mode",
+ "label": "Repository mode",
+ "description": "How runs select repositories.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "automations",
+ "writable": true,
+ "validator": "automations.automation",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "automations.automation.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "automations",
+ "resource_type": "automation_trigger",
+ "label": "Automation triggers",
+ "description": "Triggers attached to a workspace automation.",
+ "owner": "automations",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "automation_trigger.config",
+ "field_path": "config",
+ "label": "Configuration",
+ "description": "Trigger configuration.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "automations",
+ "writable": true,
+ "validator": "automations.automation_trigger",
+ "authority": "workspace.manage",
+ "sensitive": true,
+ "settings_href": "/settings"
+ },
+ {
+ "key": "automation_trigger.enabled",
+ "field_path": "enabled",
+ "label": "Enabled",
+ "description": "Whether the trigger is active.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "automations",
+ "writable": true,
+ "validator": "automations.automation_trigger",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "automations.automation_trigger.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "code_host_integrations",
+ "resource_type": "azure_devops_pull_request_watch",
+ "label": "Azure pull request watches",
+ "description": "Azure pull request watch schedules and task bindings.",
+ "owner": "azuredevops",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "requires_workspace_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "azure_devops_pull_request_watch.workflowId",
+ "field_path": "workflowId",
+ "label": "Workflow",
+ "description": "Workflow that receives matching items.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_pull_request_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_pull_request_watch.workflowStepId",
+ "field_path": "workflowStepId",
+ "label": "Workflow step",
+ "description": "Workflow step that receives matching items.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_pull_request_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_pull_request_watch.agentProfileId",
+ "field_path": "agentProfileId",
+ "label": "Agent profile",
+ "description": "Profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_pull_request_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_pull_request_watch.executorProfileId",
+ "field_path": "executorProfileId",
+ "label": "Executor profile",
+ "description": "Executor profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_pull_request_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_pull_request_watch.prompt",
+ "field_path": "prompt",
+ "label": "Prompt",
+ "description": "Prompt added to created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_pull_request_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_pull_request_watch.enabled",
+ "field_path": "enabled",
+ "label": "Enabled",
+ "description": "Whether background polling is enabled.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_pull_request_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_pull_request_watch.pollIntervalSeconds",
+ "field_path": "pollIntervalSeconds",
+ "label": "Poll interval",
+ "description": "Background polling interval in seconds.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_pull_request_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_pull_request_watch.cleanupPolicy",
+ "field_path": "cleanupPolicy",
+ "label": "Cleanup policy",
+ "description": "Policy for tasks created by this watch.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_pull_request_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_pull_request_watch.maxInflightTasks",
+ "field_path": "maxInflightTasks",
+ "label": "Concurrent task limit",
+ "description": "Maximum open tasks created by this watch, or null for unlimited.",
+ "json_type": "integer",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_pull_request_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_pull_request_watch.projectId",
+ "field_path": "projectId",
+ "label": "Project",
+ "description": "Azure DevOps project filter.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_pull_request_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_pull_request_watch.azureRepositoryId",
+ "field_path": "azureRepositoryId",
+ "label": "Azure repository",
+ "description": "Azure Repos repository filter.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_pull_request_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_pull_request_watch.status",
+ "field_path": "status",
+ "label": "Status",
+ "description": "Pull request status filter.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_pull_request_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_pull_request_watch.creatorId",
+ "field_path": "creatorId",
+ "label": "Creator",
+ "description": "Pull request creator filter.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_pull_request_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_pull_request_watch.reviewerId",
+ "field_path": "reviewerId",
+ "label": "Reviewer",
+ "description": "Pull request reviewer filter.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_pull_request_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_pull_request_watch.repositoryId",
+ "field_path": "repositoryId",
+ "label": "Repository",
+ "description": "Optional repository binding.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_pull_request_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_pull_request_watch.baseBranch",
+ "field_path": "baseBranch",
+ "label": "Base branch",
+ "description": "Base branch for the optional repository binding.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_pull_request_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "azuredevops.azure_devops_pull_request_watch.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "code_host_integrations",
+ "resource_type": "azure_devops_settings",
+ "label": "Azure DevOps settings",
+ "description": "Noncredential Azure DevOps query and action presets for one workspace.",
+ "owner": "azuredevops",
+ "scope": "workspace",
+ "target": {
+ "scope": "workspace",
+ "requires_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "azure_devops_settings.workItemQueries",
+ "field_path": "workItemQueries",
+ "label": "Work item queries",
+ "description": "Saved work item query presets.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_settings",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_settings.pullRequestQueries",
+ "field_path": "pullRequestQueries",
+ "label": "Pull request queries",
+ "description": "Saved pull request query presets.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_settings",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_settings.workItemActions",
+ "field_path": "workItemActions",
+ "label": "Work item actions",
+ "description": "Saved work item action presets.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_settings",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_settings.pullRequestActions",
+ "field_path": "pullRequestActions",
+ "label": "Pull request actions",
+ "description": "Saved pull request action presets.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_settings",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "azuredevops.azure_devops_settings.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "code_host_integrations",
+ "resource_type": "azure_devops_work_item_watch",
+ "label": "Azure work item watches",
+ "description": "Azure work item watch schedules and task bindings.",
+ "owner": "azuredevops",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "requires_workspace_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "azure_devops_work_item_watch.workflowId",
+ "field_path": "workflowId",
+ "label": "Workflow",
+ "description": "Workflow that receives matching items.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_work_item_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_work_item_watch.workflowStepId",
+ "field_path": "workflowStepId",
+ "label": "Workflow step",
+ "description": "Workflow step that receives matching items.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_work_item_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_work_item_watch.agentProfileId",
+ "field_path": "agentProfileId",
+ "label": "Agent profile",
+ "description": "Profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_work_item_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_work_item_watch.executorProfileId",
+ "field_path": "executorProfileId",
+ "label": "Executor profile",
+ "description": "Executor profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_work_item_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_work_item_watch.prompt",
+ "field_path": "prompt",
+ "label": "Prompt",
+ "description": "Prompt added to created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_work_item_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_work_item_watch.enabled",
+ "field_path": "enabled",
+ "label": "Enabled",
+ "description": "Whether background polling is enabled.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_work_item_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_work_item_watch.pollIntervalSeconds",
+ "field_path": "pollIntervalSeconds",
+ "label": "Poll interval",
+ "description": "Background polling interval in seconds.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_work_item_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_work_item_watch.cleanupPolicy",
+ "field_path": "cleanupPolicy",
+ "label": "Cleanup policy",
+ "description": "Policy for tasks created by this watch.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_work_item_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_work_item_watch.maxInflightTasks",
+ "field_path": "maxInflightTasks",
+ "label": "Concurrent task limit",
+ "description": "Maximum open tasks created by this watch, or null for unlimited.",
+ "json_type": "integer",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_work_item_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_work_item_watch.projectId",
+ "field_path": "projectId",
+ "label": "Project",
+ "description": "Azure DevOps project filter.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_work_item_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_work_item_watch.wiql",
+ "field_path": "wiql",
+ "label": "WIQL",
+ "description": "Azure Boards query.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_work_item_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_work_item_watch.repositoryId",
+ "field_path": "repositoryId",
+ "label": "Repository",
+ "description": "Optional repository binding.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_work_item_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "azure_devops_work_item_watch.baseBranch",
+ "field_path": "baseBranch",
+ "label": "Base branch",
+ "description": "Base branch for the optional repository binding.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "azuredevops",
+ "writable": true,
+ "validator": "azuredevops.azure_devops_work_item_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "azuredevops.azure_devops_work_item_watch.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "code_host_integrations",
+ "resource_type": "code_host_integration",
+ "label": "Code host integrations",
+ "description": "Use provider-specific GitHub, GitLab, and Azure DevOps resource types for settings updates.",
+ "owner": "code_host_integrations",
+ "scope": "workspace",
+ "target": {
+ "scope": "workspace",
+ "requires_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "code_host_integration.settings",
+ "field_path": "settings",
+ "label": "Provider settings",
+ "description": "Use provider-specific GitHub, GitLab, and Azure DevOps resource types for settings updates.",
+ "json_type": "object",
+ "support": "read_only",
+ "classification": "exception",
+ "owner": "code_host_integrations",
+ "exception_reason": "Provider-specific resource types preserve the provider's validation and workspace boundary.",
+ "recovery": "Use the provider-specific settings resource returned by search or target lookup."
+ }
+ ],
+ "settings_href": "/settings/integrations"
+ },
+ {
+ "domain": "editors",
+ "resource_type": "editor",
+ "label": "Editor definitions",
+ "description": "Custom editor definitions.",
+ "owner": "editors",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true
+ },
+ "fields": [
+ {
+ "key": "editor.name",
+ "field_path": "name",
+ "label": "Name",
+ "description": "Editor display name.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "editors",
+ "writable": true,
+ "validator": "editors.editor",
+ "authority": "editor.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "editor.kind",
+ "field_path": "kind",
+ "label": "Kind",
+ "description": "Custom editor kind.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "editors",
+ "writable": true,
+ "validator": "editors.editor",
+ "authority": "editor.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "editor.config",
+ "field_path": "config",
+ "label": "Configuration",
+ "description": "Validated editor configuration.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "editors",
+ "writable": true,
+ "validator": "editors.editor",
+ "authority": "editor.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "editor.enabled",
+ "field_path": "enabled",
+ "label": "Enabled",
+ "description": "Whether the editor can be selected.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "editors",
+ "writable": true,
+ "validator": "editors.editor",
+ "authority": "editor.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "editors.editor.update",
+ "authority": "editor.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "execution",
+ "resource_type": "environment",
+ "label": "Environments",
+ "description": "Execution environment definitions.",
+ "owner": "execution",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true
+ },
+ "fields": [
+ {
+ "key": "environment.name",
+ "field_path": "name",
+ "label": "Name",
+ "description": "Environment name.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.environment",
+ "authority": "execution.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "environment.kind",
+ "field_path": "kind",
+ "label": "Kind",
+ "description": "Environment kind.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.environment",
+ "authority": "execution.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "environment.worktree_root",
+ "field_path": "worktree_root",
+ "label": "Worktree root",
+ "description": "Worktree root path.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.environment",
+ "authority": "execution.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "environment.image_tag",
+ "field_path": "image_tag",
+ "label": "Image tag",
+ "description": "Container image tag.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.environment",
+ "authority": "execution.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "environment.dockerfile",
+ "field_path": "dockerfile",
+ "label": "Dockerfile",
+ "description": "Dockerfile content.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.environment",
+ "authority": "execution.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "environment.build_config",
+ "field_path": "build_config",
+ "label": "Build configuration",
+ "description": "Validated build options.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.environment",
+ "authority": "execution.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "execution.environment.update",
+ "authority": "execution.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "execution",
+ "resource_type": "executor",
+ "label": "Executors",
+ "description": "Execution target settings.",
+ "owner": "execution",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true
+ },
+ "fields": [
+ {
+ "key": "executor.name",
+ "field_path": "name",
+ "label": "Name",
+ "description": "Executor name.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.executor",
+ "authority": "execution.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "executor.type",
+ "field_path": "type",
+ "label": "Type",
+ "description": "Executor runtime type.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.executor",
+ "authority": "execution.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "executor.status",
+ "field_path": "status",
+ "label": "Status",
+ "description": "Whether the executor accepts work.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.executor",
+ "authority": "execution.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "executor.resumable",
+ "field_path": "resumable",
+ "label": "Resumable",
+ "description": "Whether sessions can resume on this executor.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.executor",
+ "authority": "execution.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "executor.config",
+ "field_path": "config",
+ "label": "Configuration",
+ "description": "Validated executor configuration.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.executor",
+ "authority": "execution.manage",
+ "sensitive": true,
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "execution.executor.update",
+ "authority": "execution.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "execution",
+ "resource_type": "executor_profile",
+ "label": "Executor profiles",
+ "description": "Named executor presets.",
+ "owner": "execution",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true
+ },
+ "fields": [
+ {
+ "key": "executor_profile.name",
+ "field_path": "name",
+ "label": "Name",
+ "description": "Profile name.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.executor_profile",
+ "authority": "execution.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "executor_profile.mcp_policy",
+ "field_path": "mcp_policy",
+ "label": "MCP policy",
+ "description": "MCP policy for this executor profile.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.executor_profile",
+ "authority": "execution.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "executor_profile.config",
+ "field_path": "config",
+ "label": "Configuration",
+ "description": "Validated executor profile configuration.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.executor_profile",
+ "authority": "execution.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "executor_profile.prepare_script",
+ "field_path": "prepare_script",
+ "label": "Prepare script",
+ "description": "Preparation command.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.executor_profile",
+ "authority": "execution.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "executor_profile.cleanup_script",
+ "field_path": "cleanup_script",
+ "label": "Cleanup script",
+ "description": "Cleanup command.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.executor_profile",
+ "authority": "execution.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "executor_profile.env_vars",
+ "field_path": "env_vars",
+ "label": "Environment variables",
+ "description": "Environment values or secret references.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "execution",
+ "writable": true,
+ "validator": "execution.executor_profile",
+ "authority": "execution.manage",
+ "sensitive": true,
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "execution.executor_profile.update",
+ "authority": "execution.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "code_host_integrations",
+ "resource_type": "github_issue_watch",
+ "label": "GitHub issue watches",
+ "description": "GitHub issue watch schedules and task bindings.",
+ "owner": "github",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "requires_workspace_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "github_issue_watch.workflow_id",
+ "field_path": "workflow_id",
+ "label": "Workflow",
+ "description": "Workflow that receives matching items.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_issue_watch.workflow_step_id",
+ "field_path": "workflow_step_id",
+ "label": "Workflow step",
+ "description": "Workflow step that receives matching items.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_issue_watch.agent_profile_id",
+ "field_path": "agent_profile_id",
+ "label": "Agent profile",
+ "description": "Profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_issue_watch.executor_profile_id",
+ "field_path": "executor_profile_id",
+ "label": "Executor profile",
+ "description": "Executor profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_issue_watch.prompt",
+ "field_path": "prompt",
+ "label": "Prompt",
+ "description": "Prompt added to created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_issue_watch.enabled",
+ "field_path": "enabled",
+ "label": "Enabled",
+ "description": "Whether background polling is enabled.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_issue_watch.poll_interval_seconds",
+ "field_path": "poll_interval_seconds",
+ "label": "Poll interval",
+ "description": "Background polling interval in seconds.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_issue_watch.cleanup_policy",
+ "field_path": "cleanup_policy",
+ "label": "Cleanup policy",
+ "description": "Policy for tasks created by this watch.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_issue_watch.repos",
+ "field_path": "repos",
+ "label": "Repositories",
+ "description": "Provider repository filters.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_issue_watch.labels",
+ "field_path": "labels",
+ "label": "Labels",
+ "description": "Issue label filters.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_issue_watch.custom_query",
+ "field_path": "custom_query",
+ "label": "Custom query",
+ "description": "Provider-specific issue query.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "github.github_issue_watch.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "code_host_integrations",
+ "resource_type": "github_review_watch",
+ "label": "GitHub review watches",
+ "description": "GitHub review watch schedules and task bindings.",
+ "owner": "github",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "requires_workspace_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "github_review_watch.workflow_id",
+ "field_path": "workflow_id",
+ "label": "Workflow",
+ "description": "Workflow that receives matching items.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_review_watch.workflow_step_id",
+ "field_path": "workflow_step_id",
+ "label": "Workflow step",
+ "description": "Workflow step that receives matching items.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_review_watch.agent_profile_id",
+ "field_path": "agent_profile_id",
+ "label": "Agent profile",
+ "description": "Profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_review_watch.executor_profile_id",
+ "field_path": "executor_profile_id",
+ "label": "Executor profile",
+ "description": "Executor profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_review_watch.prompt",
+ "field_path": "prompt",
+ "label": "Prompt",
+ "description": "Prompt added to created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_review_watch.enabled",
+ "field_path": "enabled",
+ "label": "Enabled",
+ "description": "Whether background polling is enabled.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_review_watch.poll_interval_seconds",
+ "field_path": "poll_interval_seconds",
+ "label": "Poll interval",
+ "description": "Background polling interval in seconds.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_review_watch.cleanup_policy",
+ "field_path": "cleanup_policy",
+ "label": "Cleanup policy",
+ "description": "Policy for tasks created by this watch.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_review_watch.repos",
+ "field_path": "repos",
+ "label": "Repositories",
+ "description": "Provider repository filters.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_review_watch.review_scope",
+ "field_path": "review_scope",
+ "label": "Review scope",
+ "description": "Review assignment scope.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_review_watch.custom_query",
+ "field_path": "custom_query",
+ "label": "Custom query",
+ "description": "Provider-specific review query.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "github.github_review_watch.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "code_host_integrations",
+ "resource_type": "github_settings",
+ "label": "GitHub settings",
+ "description": "Noncredential GitHub scope and query preferences for one workspace.",
+ "owner": "github",
+ "scope": "workspace",
+ "target": {
+ "scope": "workspace",
+ "requires_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "github_settings.task_git_credentials_mode",
+ "field_path": "task_git_credentials_mode",
+ "label": "Task Git credentials",
+ "description": "Credential routing mode for task worktrees.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_settings",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_settings.repo_scope_mode",
+ "field_path": "repo_scope_mode",
+ "label": "Repository scope mode",
+ "description": "Repository scope selection mode.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_settings",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_settings.repo_scope_orgs",
+ "field_path": "repo_scope_orgs",
+ "label": "Organizations",
+ "description": "Organization allowlist for repository scope.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_settings",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_settings.repo_scope_repos",
+ "field_path": "repo_scope_repos",
+ "label": "Repositories",
+ "description": "Repository allowlist for repository scope.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_settings",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_settings.saved_presets",
+ "field_path": "saved_presets",
+ "label": "Saved presets",
+ "description": "Workspace-scoped GitHub action presets.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_settings",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "github_settings.default_query_presets",
+ "field_path": "default_query_presets",
+ "label": "Default query presets",
+ "description": "Workspace-scoped GitHub query presets.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "github",
+ "writable": true,
+ "validator": "github.github_settings",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "github.github_settings.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "code_host_integrations",
+ "resource_type": "gitlab_issue_watch",
+ "label": "GitLab issue watches",
+ "description": "GitLab issue watch schedules and task bindings.",
+ "owner": "gitlab",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "requires_workspace_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "gitlab_issue_watch.workflow_id",
+ "field_path": "workflow_id",
+ "label": "Workflow",
+ "description": "Workflow that receives matching items.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_issue_watch.workflow_step_id",
+ "field_path": "workflow_step_id",
+ "label": "Workflow step",
+ "description": "Workflow step that receives matching items.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_issue_watch.agent_profile_id",
+ "field_path": "agent_profile_id",
+ "label": "Agent profile",
+ "description": "Profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_issue_watch.executor_profile_id",
+ "field_path": "executor_profile_id",
+ "label": "Executor profile",
+ "description": "Executor profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_issue_watch.prompt",
+ "field_path": "prompt",
+ "label": "Prompt",
+ "description": "Prompt added to created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_issue_watch.enabled",
+ "field_path": "enabled",
+ "label": "Enabled",
+ "description": "Whether background polling is enabled.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_issue_watch.poll_interval_seconds",
+ "field_path": "poll_interval_seconds",
+ "label": "Poll interval",
+ "description": "Background polling interval in seconds.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_issue_watch.cleanup_policy",
+ "field_path": "cleanup_policy",
+ "label": "Cleanup policy",
+ "description": "Policy for tasks created by this watch.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_issue_watch.max_inflight_tasks",
+ "field_path": "max_inflight_tasks",
+ "label": "Concurrent task limit",
+ "description": "Maximum open tasks created by this watch, or null for unlimited.",
+ "json_type": "integer",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_issue_watch.projects",
+ "field_path": "projects",
+ "label": "Projects",
+ "description": "Provider project filters.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_issue_watch.labels",
+ "field_path": "labels",
+ "label": "Labels",
+ "description": "Issue label filters.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_issue_watch.custom_query",
+ "field_path": "custom_query",
+ "label": "Custom query",
+ "description": "Provider-specific issue query.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "gitlab.gitlab_issue_watch.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "code_host_integrations",
+ "resource_type": "gitlab_review_watch",
+ "label": "GitLab review watches",
+ "description": "GitLab review watch schedules and task bindings.",
+ "owner": "gitlab",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "requires_workspace_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "gitlab_review_watch.workflow_id",
+ "field_path": "workflow_id",
+ "label": "Workflow",
+ "description": "Workflow that receives matching items.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_review_watch.workflow_step_id",
+ "field_path": "workflow_step_id",
+ "label": "Workflow step",
+ "description": "Workflow step that receives matching items.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_review_watch.agent_profile_id",
+ "field_path": "agent_profile_id",
+ "label": "Agent profile",
+ "description": "Profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_review_watch.executor_profile_id",
+ "field_path": "executor_profile_id",
+ "label": "Executor profile",
+ "description": "Executor profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_review_watch.prompt",
+ "field_path": "prompt",
+ "label": "Prompt",
+ "description": "Prompt added to created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_review_watch.enabled",
+ "field_path": "enabled",
+ "label": "Enabled",
+ "description": "Whether background polling is enabled.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_review_watch.poll_interval_seconds",
+ "field_path": "poll_interval_seconds",
+ "label": "Poll interval",
+ "description": "Background polling interval in seconds.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_review_watch.cleanup_policy",
+ "field_path": "cleanup_policy",
+ "label": "Cleanup policy",
+ "description": "Policy for tasks created by this watch.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_review_watch.max_inflight_tasks",
+ "field_path": "max_inflight_tasks",
+ "label": "Concurrent task limit",
+ "description": "Maximum open tasks created by this watch, or null for unlimited.",
+ "json_type": "integer",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_review_watch.projects",
+ "field_path": "projects",
+ "label": "Projects",
+ "description": "Provider project filters.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_review_watch.review_scope",
+ "field_path": "review_scope",
+ "label": "Review scope",
+ "description": "Review assignment scope.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "gitlab_review_watch.custom_query",
+ "field_path": "custom_query",
+ "label": "Custom query",
+ "description": "Provider-specific review query.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "gitlab",
+ "writable": true,
+ "validator": "gitlab.gitlab_review_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "gitlab.gitlab_review_watch.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "code_host_integrations",
+ "resource_type": "gitlab_settings",
+ "label": "GitLab settings",
+ "description": "Configured GitLab workspace connection metadata.",
+ "owner": "gitlab",
+ "scope": "workspace",
+ "target": {
+ "scope": "workspace",
+ "requires_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "gitlab_settings.host",
+ "field_path": "host",
+ "label": "Host",
+ "description": "Configured GitLab host. Connection identity changes use the interactive flow.",
+ "json_type": "string",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "gitlab"
+ },
+ {
+ "key": "gitlab_settings.auth_method",
+ "field_path": "auth_method",
+ "label": "Authentication method",
+ "description": "Configured GitLab authentication method.",
+ "json_type": "string",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "gitlab"
+ },
+ {
+ "key": "gitlab_settings.username",
+ "field_path": "username",
+ "label": "Username",
+ "description": "Last authenticated GitLab username.",
+ "json_type": "string",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "gitlab"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "issue_integrations",
+ "resource_type": "issue_integration",
+ "label": "Issue integrations",
+ "description": "Use provider-specific Jira, Linear, and Sentry resource types for settings updates.",
+ "owner": "issue_integrations",
+ "scope": "workspace",
+ "target": {
+ "scope": "workspace",
+ "requires_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "issue_integration.settings",
+ "field_path": "settings",
+ "label": "Provider settings",
+ "description": "Use provider-specific Jira, Linear, and Sentry resource types for settings updates.",
+ "json_type": "object",
+ "support": "read_only",
+ "classification": "exception",
+ "owner": "issue_integrations",
+ "exception_reason": "Provider-specific resource types preserve the provider's validation and workspace boundary.",
+ "recovery": "Use the provider-specific settings resource returned by search or target lookup."
+ }
+ ],
+ "settings_href": "/settings/integrations"
+ },
+ {
+ "domain": "issue_integrations",
+ "resource_type": "jira_issue_watch",
+ "label": "Jira issue watches",
+ "description": "Jira issue watch schedules and task bindings.",
+ "owner": "jira",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "requires_workspace_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "jira_issue_watch.workflowId",
+ "field_path": "workflowId",
+ "label": "Workflow",
+ "description": "Workflow that receives matching issues.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "jira",
+ "writable": true,
+ "validator": "jira.jira_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "jira_issue_watch.workflowStepId",
+ "field_path": "workflowStepId",
+ "label": "Workflow step",
+ "description": "Workflow step that receives matching issues.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "jira",
+ "writable": true,
+ "validator": "jira.jira_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "jira_issue_watch.repositoryId",
+ "field_path": "repositoryId",
+ "label": "Repository",
+ "description": "Optional repository binding for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "jira",
+ "writable": true,
+ "validator": "jira.jira_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "jira_issue_watch.baseBranch",
+ "field_path": "baseBranch",
+ "label": "Base branch",
+ "description": "Base branch for the optional repository binding.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "jira",
+ "writable": true,
+ "validator": "jira.jira_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "jira_issue_watch.agentProfileId",
+ "field_path": "agentProfileId",
+ "label": "Agent profile",
+ "description": "Profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "jira",
+ "writable": true,
+ "validator": "jira.jira_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "jira_issue_watch.executorProfileId",
+ "field_path": "executorProfileId",
+ "label": "Executor profile",
+ "description": "Executor profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "jira",
+ "writable": true,
+ "validator": "jira.jira_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "jira_issue_watch.prompt",
+ "field_path": "prompt",
+ "label": "Prompt",
+ "description": "Prompt added to created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "jira",
+ "writable": true,
+ "validator": "jira.jira_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "jira_issue_watch.enabled",
+ "field_path": "enabled",
+ "label": "Enabled",
+ "description": "Whether background polling is enabled.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "jira",
+ "writable": true,
+ "validator": "jira.jira_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "jira_issue_watch.pollIntervalSeconds",
+ "field_path": "pollIntervalSeconds",
+ "label": "Poll interval",
+ "description": "Background polling interval in seconds.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "jira",
+ "writable": true,
+ "validator": "jira.jira_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "jira_issue_watch.maxInflightTasks",
+ "field_path": "maxInflightTasks",
+ "label": "Concurrent task limit",
+ "description": "Maximum open tasks created by this watch, or null for unlimited.",
+ "json_type": "integer",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "jira",
+ "writable": true,
+ "validator": "jira.jira_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "jira_issue_watch.jql",
+ "field_path": "jql",
+ "label": "Filter",
+ "description": "Provider-specific issue filter.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "jira",
+ "writable": true,
+ "validator": "jira.jira_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "jira.jira_issue_watch.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "issue_integrations",
+ "resource_type": "jira_settings",
+ "label": "Jira settings",
+ "description": "Noncredential Jira defaults for one workspace.",
+ "owner": "jira",
+ "scope": "workspace",
+ "target": {
+ "scope": "workspace",
+ "requires_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "jira_settings.defaultProjectKey",
+ "field_path": "defaultProjectKey",
+ "label": "Default project",
+ "description": "Default Jira project key for issue workflows.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "jira",
+ "writable": true,
+ "validator": "jira.jira_settings",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "jira_settings.siteUrl",
+ "field_path": "siteUrl",
+ "label": "Site URL",
+ "description": "Configured Jira site identity. Credential and identity changes use the connection flow.",
+ "json_type": "string",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "jira"
+ },
+ {
+ "key": "jira_settings.email",
+ "field_path": "email",
+ "label": "Account email",
+ "description": "Configured Jira account metadata.",
+ "json_type": "string",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "jira"
+ },
+ {
+ "key": "jira_settings.authMethod",
+ "field_path": "authMethod",
+ "label": "Authentication method",
+ "description": "Configured Jira authentication method.",
+ "json_type": "string",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "jira"
+ },
+ {
+ "key": "jira_settings.instanceType",
+ "field_path": "instanceType",
+ "label": "Instance type",
+ "description": "Configured Jira deployment type.",
+ "json_type": "string",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "jira"
+ },
+ {
+ "key": "jira_settings.hasSecret",
+ "field_path": "hasSecret",
+ "label": "Credential present",
+ "description": "Whether a credential is enrolled, without exposing it.",
+ "json_type": "boolean",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "jira"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "jira.jira_settings.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "issue_integrations",
+ "resource_type": "linear_issue_watch",
+ "label": "Linear issue watches",
+ "description": "Linear issue watch schedules and task bindings.",
+ "owner": "linear",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "requires_workspace_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "linear_issue_watch.workflowId",
+ "field_path": "workflowId",
+ "label": "Workflow",
+ "description": "Workflow that receives matching issues.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "linear",
+ "writable": true,
+ "validator": "linear.linear_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "linear_issue_watch.workflowStepId",
+ "field_path": "workflowStepId",
+ "label": "Workflow step",
+ "description": "Workflow step that receives matching issues.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "linear",
+ "writable": true,
+ "validator": "linear.linear_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "linear_issue_watch.repositoryId",
+ "field_path": "repositoryId",
+ "label": "Repository",
+ "description": "Optional repository binding for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "linear",
+ "writable": true,
+ "validator": "linear.linear_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "linear_issue_watch.baseBranch",
+ "field_path": "baseBranch",
+ "label": "Base branch",
+ "description": "Base branch for the optional repository binding.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "linear",
+ "writable": true,
+ "validator": "linear.linear_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "linear_issue_watch.agentProfileId",
+ "field_path": "agentProfileId",
+ "label": "Agent profile",
+ "description": "Profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "linear",
+ "writable": true,
+ "validator": "linear.linear_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "linear_issue_watch.executorProfileId",
+ "field_path": "executorProfileId",
+ "label": "Executor profile",
+ "description": "Executor profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "linear",
+ "writable": true,
+ "validator": "linear.linear_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "linear_issue_watch.prompt",
+ "field_path": "prompt",
+ "label": "Prompt",
+ "description": "Prompt added to created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "linear",
+ "writable": true,
+ "validator": "linear.linear_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "linear_issue_watch.enabled",
+ "field_path": "enabled",
+ "label": "Enabled",
+ "description": "Whether background polling is enabled.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "linear",
+ "writable": true,
+ "validator": "linear.linear_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "linear_issue_watch.pollIntervalSeconds",
+ "field_path": "pollIntervalSeconds",
+ "label": "Poll interval",
+ "description": "Background polling interval in seconds.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "linear",
+ "writable": true,
+ "validator": "linear.linear_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "linear_issue_watch.maxInflightTasks",
+ "field_path": "maxInflightTasks",
+ "label": "Concurrent task limit",
+ "description": "Maximum open tasks created by this watch, or null for unlimited.",
+ "json_type": "integer",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "linear",
+ "writable": true,
+ "validator": "linear.linear_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "linear_issue_watch.filter",
+ "field_path": "filter",
+ "label": "Filter",
+ "description": "Provider-specific issue filter.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "linear",
+ "writable": true,
+ "validator": "linear.linear_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "linear_issue_watch.sortBy",
+ "field_path": "sortBy",
+ "label": "Sort order",
+ "description": "Order in which matching Linear issues are dispatched.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "linear",
+ "writable": true,
+ "validator": "linear.linear_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "linear.linear_issue_watch.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "issue_integrations",
+ "resource_type": "linear_settings",
+ "label": "Linear settings",
+ "description": "Noncredential Linear defaults for one workspace.",
+ "owner": "linear",
+ "scope": "workspace",
+ "target": {
+ "scope": "workspace",
+ "requires_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "linear_settings.defaultTeamKey",
+ "field_path": "defaultTeamKey",
+ "label": "Default team",
+ "description": "Default Linear team key for issue workflows.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "linear",
+ "writable": true,
+ "validator": "linear.linear_settings",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "linear_settings.authMethod",
+ "field_path": "authMethod",
+ "label": "Authentication method",
+ "description": "Configured Linear authentication method.",
+ "json_type": "string",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "linear"
+ },
+ {
+ "key": "linear_settings.orgSlug",
+ "field_path": "orgSlug",
+ "label": "Organization slug",
+ "description": "Computed Linear organization metadata.",
+ "json_type": "string",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "linear"
+ },
+ {
+ "key": "linear_settings.hasSecret",
+ "field_path": "hasSecret",
+ "label": "Credential present",
+ "description": "Whether a credential is enrolled, without exposing it.",
+ "json_type": "boolean",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "linear"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "linear.linear_settings.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "notifications",
+ "resource_type": "notification_provider",
+ "label": "Notification providers",
+ "description": "Notification provider settings and subscriptions.",
+ "owner": "notifications",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true
+ },
+ "fields": [
+ {
+ "key": "notification_provider.name",
+ "field_path": "name",
+ "label": "Name",
+ "description": "Provider name.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "notifications",
+ "writable": true,
+ "validator": "notifications.notification_provider",
+ "authority": "notification.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "notification_provider.type",
+ "field_path": "type",
+ "label": "Type",
+ "description": "Provider type.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "notifications",
+ "writable": true,
+ "validator": "notifications.notification_provider",
+ "authority": "notification.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "notification_provider.config",
+ "field_path": "config",
+ "label": "Configuration",
+ "description": "Validated provider configuration.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "notifications",
+ "writable": true,
+ "validator": "notifications.notification_provider",
+ "authority": "notification.manage",
+ "sensitive": true,
+ "settings_href": "/settings"
+ },
+ {
+ "key": "notification_provider.enabled",
+ "field_path": "enabled",
+ "label": "Enabled",
+ "description": "Whether notifications are enabled.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "notifications",
+ "writable": true,
+ "validator": "notifications.notification_provider",
+ "authority": "notification.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "notification_provider.events",
+ "field_path": "events",
+ "label": "Events",
+ "description": "Subscribed event types.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "notifications",
+ "writable": true,
+ "validator": "notifications.notification_provider",
+ "authority": "notification.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "notifications.notification_provider.update",
+ "authority": "notification.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "prompts",
+ "resource_type": "prompt",
+ "label": "Saved prompts",
+ "description": "Saved prompt definitions.",
+ "owner": "prompts",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true
+ },
+ "fields": [
+ {
+ "key": "prompt.name",
+ "field_path": "name",
+ "label": "Name",
+ "description": "Prompt name.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "prompts",
+ "writable": true,
+ "validator": "prompts.prompt",
+ "authority": "prompt.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "prompt.content",
+ "field_path": "content",
+ "label": "Content",
+ "description": "Prompt content.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "prompts",
+ "writable": true,
+ "validator": "prompts.prompt",
+ "authority": "prompt.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "prompts.prompt.update",
+ "authority": "prompt.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "workspaces",
+ "resource_type": "repository",
+ "label": "Repositories",
+ "description": "Workspace repository settings.",
+ "owner": "workspace",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "repository.name",
+ "field_path": "name",
+ "label": "Name",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.source_type",
+ "field_path": "source_type",
+ "label": "Source type",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.local_path",
+ "field_path": "local_path",
+ "label": "Local path",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.provider",
+ "field_path": "provider",
+ "label": "Provider",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.provider_repo_id",
+ "field_path": "provider_repo_id",
+ "label": "Provider repository ID",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.provider_host",
+ "field_path": "provider_host",
+ "label": "Provider host",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.provider_scope",
+ "field_path": "provider_scope",
+ "label": "Provider scope",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.provider_owner",
+ "field_path": "provider_owner",
+ "label": "Provider owner",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.provider_name",
+ "field_path": "provider_name",
+ "label": "Provider name",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.remote_url",
+ "field_path": "remote_url",
+ "label": "Remote URL",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.default_branch",
+ "field_path": "default_branch",
+ "label": "Default branch",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.worktree_branch_prefix",
+ "field_path": "worktree_branch_prefix",
+ "label": "Branch prefix",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.worktree_branch_template",
+ "field_path": "worktree_branch_template",
+ "label": "Branch template",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.pull_before_worktree",
+ "field_path": "pull_before_worktree",
+ "label": "Pull before worktree",
+ "description": "Repository setting.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.setup_script",
+ "field_path": "setup_script",
+ "label": "Setup script",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.cleanup_script",
+ "field_path": "cleanup_script",
+ "label": "Cleanup script",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.dev_script",
+ "field_path": "dev_script",
+ "label": "Development script",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.copy_files",
+ "field_path": "copy_files",
+ "label": "Copy files",
+ "description": "Repository setting.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository.secret_bindings",
+ "field_path": "secret_bindings",
+ "label": "Secret bindings",
+ "description": "Repository setting.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository",
+ "authority": "workspace.manage",
+ "sensitive": true,
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "workspace.repository.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "workspaces",
+ "resource_type": "repository_script",
+ "label": "Repository scripts",
+ "description": "Custom repository commands.",
+ "owner": "workspace",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "repository_script.name",
+ "field_path": "name",
+ "label": "Name",
+ "description": "Script name.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository_script",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository_script.command",
+ "field_path": "command",
+ "label": "Command",
+ "description": "Script command.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository_script",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository_script.position",
+ "field_path": "position",
+ "label": "Position",
+ "description": "Script ordering is controlled by the repository script reorder action.",
+ "json_type": "integer",
+ "support": "exception",
+ "classification": "action",
+ "owner": "workspace",
+ "settings_href": "/settings",
+ "exception_reason": "Script ordering is controlled by the repository script reorder action.",
+ "recovery": "Use the repository script reorder action."
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "workspace.repository_script.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "workspaces",
+ "resource_type": "repository_set",
+ "label": "Repository sets",
+ "description": "Reusable repository selections.",
+ "owner": "workspace",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "repository_set.name",
+ "field_path": "name",
+ "label": "Name",
+ "description": "Repository set name.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository_set",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository_set.description",
+ "field_path": "description",
+ "label": "Description",
+ "description": "Repository set description.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository_set",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "repository_set.repository_ids",
+ "field_path": "repository_ids",
+ "label": "Repositories",
+ "description": "Ordered repository membership.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.repository_set",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "workspace.repository_set.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "runtime",
+ "resource_type": "runtime_flag",
+ "label": "Runtime overrides",
+ "description": "Permitted persisted runtime flag overrides.",
+ "owner": "runtime",
+ "scope": "installation",
+ "target": {
+ "scope": "installation",
+ "requires_resource_id": true
+ },
+ "fields": [
+ {
+ "key": "runtime_flag.override",
+ "field_path": "override",
+ "label": "Override",
+ "description": "Explicit persisted runtime override. Null clears the override.",
+ "json_type": "boolean",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "runtime",
+ "writable": true,
+ "validator": "runtime.runtime_flag",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "runtime.runtime_flag.update",
+ "authority": "org.settings.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "issue_integrations",
+ "resource_type": "sentry_instance",
+ "label": "Sentry instances",
+ "description": "Named noncredential Sentry instance settings.",
+ "owner": "sentry",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "requires_workspace_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "sentry_instance.name",
+ "field_path": "name",
+ "label": "Name",
+ "description": "Display name for the Sentry instance.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "sentry",
+ "writable": true,
+ "validator": "sentry.sentry_instance",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "sentry_instance.url",
+ "field_path": "url",
+ "label": "URL",
+ "description": "Configured Sentry instance identity. Connection changes use the interactive flow.",
+ "json_type": "string",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "sentry"
+ },
+ {
+ "key": "sentry_instance.authMethod",
+ "field_path": "authMethod",
+ "label": "Authentication method",
+ "description": "Configured Sentry authentication method.",
+ "json_type": "string",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "sentry"
+ },
+ {
+ "key": "sentry_instance.hasSecret",
+ "field_path": "hasSecret",
+ "label": "Credential present",
+ "description": "Whether a credential is enrolled, without exposing it.",
+ "json_type": "boolean",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "sentry"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "sentry.sentry_instance.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "issue_integrations",
+ "resource_type": "sentry_issue_watch",
+ "label": "Sentry issue watches",
+ "description": "Sentry issue watch schedules and task bindings.",
+ "owner": "sentry",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "requires_workspace_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "sentry_issue_watch.workflowId",
+ "field_path": "workflowId",
+ "label": "Workflow",
+ "description": "Workflow that receives matching issues.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "sentry",
+ "writable": true,
+ "validator": "sentry.sentry_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "sentry_issue_watch.workflowStepId",
+ "field_path": "workflowStepId",
+ "label": "Workflow step",
+ "description": "Workflow step that receives matching issues.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "sentry",
+ "writable": true,
+ "validator": "sentry.sentry_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "sentry_issue_watch.repositoryId",
+ "field_path": "repositoryId",
+ "label": "Repository",
+ "description": "Optional repository binding for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "sentry",
+ "writable": true,
+ "validator": "sentry.sentry_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "sentry_issue_watch.baseBranch",
+ "field_path": "baseBranch",
+ "label": "Base branch",
+ "description": "Base branch for the optional repository binding.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "sentry",
+ "writable": true,
+ "validator": "sentry.sentry_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "sentry_issue_watch.agentProfileId",
+ "field_path": "agentProfileId",
+ "label": "Agent profile",
+ "description": "Profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "sentry",
+ "writable": true,
+ "validator": "sentry.sentry_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "sentry_issue_watch.executorProfileId",
+ "field_path": "executorProfileId",
+ "label": "Executor profile",
+ "description": "Executor profile used for created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "sentry",
+ "writable": true,
+ "validator": "sentry.sentry_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "sentry_issue_watch.prompt",
+ "field_path": "prompt",
+ "label": "Prompt",
+ "description": "Prompt added to created tasks.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "sentry",
+ "writable": true,
+ "validator": "sentry.sentry_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "sentry_issue_watch.enabled",
+ "field_path": "enabled",
+ "label": "Enabled",
+ "description": "Whether background polling is enabled.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "sentry",
+ "writable": true,
+ "validator": "sentry.sentry_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "sentry_issue_watch.pollIntervalSeconds",
+ "field_path": "pollIntervalSeconds",
+ "label": "Poll interval",
+ "description": "Background polling interval in seconds.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "sentry",
+ "writable": true,
+ "validator": "sentry.sentry_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "sentry_issue_watch.maxInflightTasks",
+ "field_path": "maxInflightTasks",
+ "label": "Concurrent task limit",
+ "description": "Maximum open tasks created by this watch, or null for unlimited.",
+ "json_type": "integer",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "sentry",
+ "writable": true,
+ "validator": "sentry.sentry_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "sentry_issue_watch.filter",
+ "field_path": "filter",
+ "label": "Filter",
+ "description": "Provider-specific issue filter.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "sentry",
+ "writable": true,
+ "validator": "sentry.sentry_issue_watch",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "sentry.sentry_issue_watch.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "storage",
+ "resource_type": "storage_maintenance",
+ "label": "Storage maintenance",
+ "description": "Install-wide storage maintenance policy.",
+ "owner": "storage",
+ "scope": "installation",
+ "target": {
+ "scope": "installation",
+ "singleton": true
+ },
+ "fields": [
+ {
+ "key": "storage_maintenance.enabled",
+ "field_path": "enabled",
+ "label": "Enabled",
+ "description": "Storage maintenance policy.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "storage",
+ "writable": true,
+ "validator": "storage.storage_maintenance",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "storage_maintenance.check_interval_hours",
+ "field_path": "check_interval_hours",
+ "label": "Check interval",
+ "description": "Storage maintenance policy.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "storage",
+ "writable": true,
+ "validator": "storage.storage_maintenance",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "storage_maintenance.idle_for_minutes",
+ "field_path": "idle_for_minutes",
+ "label": "Idle period",
+ "description": "Storage maintenance policy.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "storage",
+ "writable": true,
+ "validator": "storage.storage_maintenance",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "storage_maintenance.orphan_grace_hours",
+ "field_path": "orphan_grace_hours",
+ "label": "Orphan grace",
+ "description": "Storage maintenance policy.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "storage",
+ "writable": true,
+ "validator": "storage.storage_maintenance",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "storage_maintenance.quarantine_retention_hours",
+ "field_path": "quarantine_retention_hours",
+ "label": "Quarantine retention",
+ "description": "Storage maintenance policy.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "storage",
+ "writable": true,
+ "validator": "storage.storage_maintenance",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "storage_maintenance.workspaces.enabled",
+ "field_path": "workspaces.enabled",
+ "label": "Workspace cleanup",
+ "description": "Storage maintenance policy.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "storage",
+ "writable": true,
+ "validator": "storage.storage_maintenance",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "storage_maintenance.workspaces.dependency_cleanup_enabled",
+ "field_path": "workspaces.dependency_cleanup_enabled",
+ "label": "Dependency cleanup",
+ "description": "Storage maintenance policy.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "storage",
+ "writable": true,
+ "validator": "storage.storage_maintenance",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "storage_maintenance.kandev_containers.enabled",
+ "field_path": "kandev_containers.enabled",
+ "label": "Kandev containers",
+ "description": "Storage maintenance policy.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "storage",
+ "writable": true,
+ "validator": "storage.storage_maintenance",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "storage_maintenance.go_cache.enabled",
+ "field_path": "go_cache.enabled",
+ "label": "Go cache",
+ "description": "Storage maintenance policy.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "storage",
+ "writable": true,
+ "validator": "storage.storage_maintenance",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "storage_maintenance.go_cache.max_bytes",
+ "field_path": "go_cache.max_bytes",
+ "label": "Go cache limit",
+ "description": "Storage maintenance policy.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "storage",
+ "writable": true,
+ "validator": "storage.storage_maintenance",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "storage_maintenance.docker.dedicated_daemon_acknowledged",
+ "field_path": "docker.dedicated_daemon_acknowledged",
+ "label": "Dedicated Docker acknowledgement",
+ "description": "Storage maintenance policy.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "storage",
+ "writable": true,
+ "validator": "storage.storage_maintenance",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "storage_maintenance.docker.build_cache_enabled",
+ "field_path": "docker.build_cache_enabled",
+ "label": "Docker build cache",
+ "description": "Storage maintenance policy.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "storage",
+ "writable": true,
+ "validator": "storage.storage_maintenance",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "storage_maintenance.docker.build_cache_keep_bytes",
+ "field_path": "docker.build_cache_keep_bytes",
+ "label": "Docker build cache limit",
+ "description": "Storage maintenance policy.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "storage",
+ "writable": true,
+ "validator": "storage.storage_maintenance",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "storage_maintenance.docker.build_cache_unused_hours",
+ "field_path": "docker.build_cache_unused_hours",
+ "label": "Docker build cache age",
+ "description": "Storage maintenance policy.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "storage",
+ "writable": true,
+ "validator": "storage.storage_maintenance",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "storage_maintenance.docker.unused_images_enabled",
+ "field_path": "docker.unused_images_enabled",
+ "label": "Unused image cleanup",
+ "description": "Storage maintenance policy.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "storage",
+ "writable": true,
+ "validator": "storage.storage_maintenance",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "storage_maintenance.docker.unused_images_hours",
+ "field_path": "docker.unused_images_hours",
+ "label": "Unused image age",
+ "description": "Storage maintenance policy.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "storage",
+ "writable": true,
+ "validator": "storage.storage_maintenance",
+ "authority": "org.settings.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "storage.storage_maintenance.update",
+ "authority": "org.settings.manage",
+ "options": {
+ "additionalProperties": false,
+ "properties": {
+ "adopt_go_cache": {
+ "type": "boolean"
+ },
+ "confirm_dedicated_docker": {
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ }
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "tasks",
+ "resource_type": "task",
+ "label": "Tasks",
+ "description": "Permitted saved task configuration.",
+ "owner": "task",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "task.title",
+ "field_path": "title",
+ "label": "Title",
+ "description": "Task title.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "task",
+ "writable": true,
+ "validator": "task.task",
+ "authority": "task.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "task.description",
+ "field_path": "description",
+ "label": "Description",
+ "description": "Task description.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "task",
+ "writable": true,
+ "validator": "task.task",
+ "authority": "task.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "task.priority",
+ "field_path": "priority",
+ "label": "Priority",
+ "description": "Task priority.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "task",
+ "writable": true,
+ "validator": "task.task",
+ "authority": "task.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "task.workflow_step_id",
+ "field_path": "workflow_step_id",
+ "label": "Workflow step",
+ "description": "Task movement is controlled by the task lifecycle action.",
+ "json_type": "string",
+ "support": "exception",
+ "classification": "action",
+ "owner": "task",
+ "settings_href": "/settings",
+ "exception_reason": "Task movement is controlled by the task lifecycle action.",
+ "recovery": "Use the task move action."
+ },
+ {
+ "key": "task.position",
+ "field_path": "position",
+ "label": "Position",
+ "description": "Task ordering is controlled by the task reorder action.",
+ "json_type": "integer",
+ "support": "exception",
+ "classification": "action",
+ "owner": "task",
+ "settings_href": "/settings",
+ "exception_reason": "Task ordering is controlled by the task reorder action.",
+ "recovery": "Use the task reorder action."
+ },
+ {
+ "key": "task.metadata",
+ "field_path": "metadata",
+ "label": "Metadata",
+ "description": "Open-ended task metadata is controlled by domain-specific task operations.",
+ "json_type": "object",
+ "support": "exception",
+ "classification": "exception",
+ "owner": "task",
+ "settings_href": "/settings",
+ "exception_reason": "Open-ended task metadata is controlled by domain-specific task operations.",
+ "recovery": "Use the task metadata operation for a known metadata key."
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "task.task.update",
+ "authority": "task.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "user_preferences",
+ "resource_type": "user_settings",
+ "label": "Personal preferences",
+ "description": "Portable settings belonging to the authenticated user.",
+ "owner": "user-settings",
+ "scope": "caller",
+ "target": {
+ "scope": "caller",
+ "singleton": true
+ },
+ "fields": [
+ {
+ "key": "user_settings.workspace_id",
+ "field_path": "workspace_id",
+ "label": "workspace",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.kanban_view_mode",
+ "field_path": "kanban_view_mode",
+ "label": "kanban view mode",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.startup_page",
+ "field_path": "startup_page",
+ "label": "startup page",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.workflow_filter_id",
+ "field_path": "workflow_filter_id",
+ "label": "workflow filter",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.repository_ids",
+ "field_path": "repository_ids",
+ "label": "repository selection",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.tasks_list_sort",
+ "field_path": "tasks_list_sort",
+ "label": "task sort",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.tasks_list_group",
+ "field_path": "tasks_list_group",
+ "label": "task grouping",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.tasks_list_show_details",
+ "field_path": "tasks_list_show_details",
+ "label": "task details",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.initial_setup_complete",
+ "field_path": "initial_setup_complete",
+ "label": "setup complete",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.preferred_shell",
+ "field_path": "preferred_shell",
+ "label": "preferred shell",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.default_editor_id",
+ "field_path": "default_editor_id",
+ "label": "default editor",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.enable_preview_on_click",
+ "field_path": "enable_preview_on_click",
+ "label": "preview on click",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.chat_submit_key",
+ "field_path": "chat_submit_key",
+ "label": "chat submit key",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.review_auto_mark_on_scroll",
+ "field_path": "review_auto_mark_on_scroll",
+ "label": "review auto mark",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.confirm_task_archive",
+ "field_path": "confirm_task_archive",
+ "label": "confirm task archive",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.prevent_auto_start_agent_on_open",
+ "field_path": "prevent_auto_start_agent_on_open",
+ "label": "prevent auto start",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.unread_divider",
+ "field_path": "unread_divider",
+ "label": "unread divider",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.agent_generated_task_titles",
+ "field_path": "agent_generated_task_titles",
+ "label": "generated titles",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.mcp_task_agent_profile_default",
+ "field_path": "mcp_task_agent_profile_default",
+ "label": "MCP task profile",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.show_anchored_prompt_bar",
+ "field_path": "show_anchored_prompt_bar",
+ "label": "anchored prompt bar",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.show_scroll_to_last_prompt",
+ "field_path": "show_scroll_to_last_prompt",
+ "label": "scroll to last prompt",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.show_scroll_to_start",
+ "field_path": "show_scroll_to_start",
+ "label": "scroll to start",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.show_transcript_auto_scroll_control",
+ "field_path": "show_transcript_auto_scroll_control",
+ "label": "transcript scroll control",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.show_todo_list_panel",
+ "field_path": "show_todo_list_panel",
+ "label": "todo list panel",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.show_todo_list_panel_only_when_not_empty",
+ "field_path": "show_todo_list_panel_only_when_not_empty",
+ "label": "todo list empty state",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.show_release_notification",
+ "field_path": "show_release_notification",
+ "label": "release notification",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.release_notes_last_seen_version",
+ "field_path": "release_notes_last_seen_version",
+ "label": "release notes version",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.lsp_auto_start_languages",
+ "field_path": "lsp_auto_start_languages",
+ "label": "LSP auto start",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.lsp_auto_install_languages",
+ "field_path": "lsp_auto_install_languages",
+ "label": "LSP auto install",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.lsp_server_configs",
+ "field_path": "lsp_server_configs",
+ "label": "LSP server configs",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.lsp_status_location",
+ "field_path": "lsp_status_location",
+ "label": "LSP status location",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.saved_layouts",
+ "field_path": "saved_layouts",
+ "label": "saved layouts",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.sidebar_views",
+ "field_path": "sidebar_views",
+ "label": "sidebar views",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.sidebar_active_view_id",
+ "field_path": "sidebar_active_view_id",
+ "label": "active sidebar view",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.sidebar_draft",
+ "field_path": "sidebar_draft",
+ "label": "sidebar draft",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.thread_views",
+ "field_path": "thread_views",
+ "label": "thread views",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.thread_active_view_id",
+ "field_path": "thread_active_view_id",
+ "label": "active thread view",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.thread_view_draft",
+ "field_path": "thread_view_draft",
+ "label": "thread draft",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.sidebar_task_prefs",
+ "field_path": "sidebar_task_prefs",
+ "label": "sidebar task preferences",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.sidebar_task_color_automation",
+ "field_path": "sidebar_task_color_automation",
+ "label": "sidebar color automation",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.sidebar_task_colors",
+ "field_path": "sidebar_task_colors",
+ "label": "sidebar task colors",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.sidebar_task_color_patch",
+ "field_path": "sidebar_task_color_patch",
+ "label": "sidebar task color patch",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences",
+ "schema": {
+ "additionalProperties": false,
+ "properties": {
+ "colors": {
+ "additionalProperties": {
+ "nullable": true,
+ "type": "string"
+ },
+ "type": "object"
+ },
+ "if_missing": {
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ }
+ },
+ {
+ "key": "user_settings.task_create_last_used",
+ "field_path": "task_create_last_used",
+ "label": "last task create values",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.jira_saved_views",
+ "field_path": "jira_saved_views",
+ "label": "Jira saved views",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.jira_task_presets",
+ "field_path": "jira_task_presets",
+ "label": "Jira task presets",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.github_saved_presets",
+ "field_path": "github_saved_presets",
+ "label": "GitHub saved presets",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.github_default_query_presets",
+ "field_path": "github_default_query_presets",
+ "label": "GitHub query presets",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.gitlab_saved_presets",
+ "field_path": "gitlab_saved_presets",
+ "label": "GitLab saved presets",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.azure_devops_browse_preferences",
+ "field_path": "azure_devops_browse_preferences",
+ "label": "Azure DevOps browse preferences",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "nullable": true,
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.default_utility_agent_id",
+ "field_path": "default_utility_agent_id",
+ "label": "default utility agent",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.default_utility_model",
+ "field_path": "default_utility_model",
+ "label": "default utility model",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.default_utility_agent_profile_id",
+ "field_path": "default_utility_agent_profile_id",
+ "label": "default utility profile",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.keyboard_shortcuts",
+ "field_path": "keyboard_shortcuts",
+ "label": "keyboard shortcuts",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences",
+ "schema": {
+ "additionalProperties": {
+ "additionalProperties": false,
+ "properties": {
+ "key": {
+ "type": "string"
+ },
+ "modifiers": {
+ "additionalProperties": false,
+ "properties": {
+ "alt": {
+ "type": "boolean"
+ },
+ "command": {
+ "type": "boolean"
+ },
+ "ctrl": {
+ "type": "boolean"
+ },
+ "meta": {
+ "type": "boolean"
+ },
+ "shift": {
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ }
+ },
+ "type": "object"
+ },
+ "type": "object"
+ }
+ },
+ {
+ "key": "user_settings.terminal_link_behavior",
+ "field_path": "terminal_link_behavior",
+ "label": "terminal link behavior",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.terminal_font_family",
+ "field_path": "terminal_font_family",
+ "label": "terminal font family",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.terminal_font_size",
+ "field_path": "terminal_font_size",
+ "label": "terminal font size",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.changes_panel_layout",
+ "field_path": "changes_panel_layout",
+ "label": "changes panel layout",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.last_seen_display",
+ "field_path": "last_seen_display",
+ "label": "last seen display",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.system_metrics_display",
+ "field_path": "system_metrics_display",
+ "label": "system metrics display",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.app_status_bar_enabled",
+ "field_path": "app_status_bar_enabled",
+ "label": "status bar",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.resolve_session_hostnames",
+ "field_path": "resolve_session_hostnames",
+ "label": "resolve hostnames",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.app_status_bar_order",
+ "field_path": "app_status_bar_order",
+ "label": "status bar order",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.quick_chat_tab_order_by_workspace",
+ "field_path": "quick_chat_tab_order_by_workspace",
+ "label": "quick chat tab order",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.kanban_hidden_step_ids",
+ "field_path": "kanban_hidden_step_ids",
+ "label": "hidden kanban steps",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "key": "user_settings.workflow_ids_with_auto_hide_empty_steps",
+ "field_path": "workflow_ids_with_auto_hide_empty_steps",
+ "label": "auto-hide workflows",
+ "description": "Portable preference owned by the current user.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "user-settings",
+ "writable": true,
+ "validator": "user-settings",
+ "authority": "user.self",
+ "change_timing": "future_views",
+ "settings_href": "/settings/preferences"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "user-settings.update",
+ "authority": "user.self"
+ }
+ ],
+ "settings_href": "/settings/preferences"
+ },
+ {
+ "domain": "utilities",
+ "resource_type": "utility_agent",
+ "label": "Utility agents",
+ "description": "Utility agent definitions.",
+ "owner": "utilities",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true
+ },
+ "fields": [
+ {
+ "key": "utility_agent.name",
+ "field_path": "name",
+ "label": "Name",
+ "description": "Utility name.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "utilities",
+ "writable": true,
+ "validator": "utilities.utility_agent",
+ "authority": "utility.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "utility_agent.description",
+ "field_path": "description",
+ "label": "Description",
+ "description": "Utility description.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "utilities",
+ "writable": true,
+ "validator": "utilities.utility_agent",
+ "authority": "utility.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "utility_agent.prompt",
+ "field_path": "prompt",
+ "label": "Prompt",
+ "description": "Utility prompt template.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "utilities",
+ "writable": true,
+ "validator": "utilities.utility_agent",
+ "authority": "utility.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "utility_agent.agent_id",
+ "field_path": "agent_id",
+ "label": "Agent",
+ "description": "Inference agent identifier.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "utilities",
+ "writable": true,
+ "validator": "utilities.utility_agent",
+ "authority": "utility.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "utility_agent.model",
+ "field_path": "model",
+ "label": "Model",
+ "description": "Default model.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "utilities",
+ "writable": true,
+ "validator": "utilities.utility_agent",
+ "authority": "utility.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "utility_agent.agent_profile_id",
+ "field_path": "agent_profile_id",
+ "label": "Agent profile",
+ "description": "Profile binding.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "utilities",
+ "writable": true,
+ "validator": "utilities.utility_agent",
+ "authority": "utility.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "utility_agent.profile_binding_state",
+ "field_path": "profile_binding_state",
+ "label": "Profile binding state",
+ "description": "Profile inheritance state.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "utilities",
+ "writable": true,
+ "validator": "utilities.utility_agent",
+ "authority": "utility.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "utility_agent.enabled",
+ "field_path": "enabled",
+ "label": "Enabled",
+ "description": "Whether the utility is available.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "utilities",
+ "writable": true,
+ "validator": "utilities.utility_agent",
+ "authority": "utility.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "utilities.utility_agent.update",
+ "authority": "utility.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "workflows",
+ "resource_type": "workflow",
+ "label": "Workflows",
+ "description": "Saved workflow definitions.",
+ "owner": "workflow",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "workflow.name",
+ "field_path": "name",
+ "label": "Name",
+ "description": "Workflow name.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow.description",
+ "field_path": "description",
+ "label": "Description",
+ "description": "Workflow description.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow.prompt",
+ "field_path": "prompt",
+ "label": "Prompt",
+ "description": "Workflow-level instructions.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow.agent_profile_id",
+ "field_path": "agent_profile_id",
+ "label": "Agent profile",
+ "description": "Profile used by the workflow when configured.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "workflow.workflow.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "workflows",
+ "resource_type": "workflow_step",
+ "label": "Workflow steps",
+ "description": "Editable steps in a saved workflow.",
+ "owner": "workflow",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "workflow_step.name",
+ "field_path": "name",
+ "label": "Name",
+ "description": "Step name.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow_step",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow_step.position",
+ "field_path": "position",
+ "label": "Position",
+ "description": "Step ordering is controlled by the workflow reorder action.",
+ "json_type": "integer",
+ "support": "exception",
+ "classification": "action",
+ "owner": "workflow",
+ "settings_href": "/settings",
+ "exception_reason": "Step ordering is controlled by the workflow reorder action.",
+ "recovery": "Use the workflow step reorder action."
+ },
+ {
+ "key": "workflow_step.color",
+ "field_path": "color",
+ "label": "Color",
+ "description": "Step display color.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow_step",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow_step.prompt",
+ "field_path": "prompt",
+ "label": "Prompt",
+ "description": "Step instructions.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow_step",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow_step.events",
+ "field_path": "events",
+ "label": "Events",
+ "description": "Validated step event actions and bindings.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow_step",
+ "authority": "workspace.manage",
+ "settings_href": "/settings",
+ "schema": {
+ "additionalProperties": false,
+ "properties": {
+ "on_agent_error": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "config": {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ "type": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "on_approval_resolved": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "config": {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ "type": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "on_blocker_resolved": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "config": {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ "type": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "on_budget_alert": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "config": {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ "type": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "on_children_completed": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "config": {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ "type": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "on_comment": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "config": {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ "type": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "on_enter": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "config": {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ "type": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "on_exit": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "config": {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ "type": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "on_heartbeat": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "config": {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ "type": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "on_turn_complete": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "config": {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ "type": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "on_turn_start": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "config": {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ "type": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ }
+ },
+ "type": "object"
+ }
+ },
+ {
+ "key": "workflow_step.allow_manual_move",
+ "field_path": "allow_manual_move",
+ "label": "Manual move",
+ "description": "Whether users may move tasks into this step.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow_step",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow_step.is_start_step",
+ "field_path": "is_start_step",
+ "label": "Start step",
+ "description": "Whether this is the workflow start step.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow_step",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow_step.show_in_command_panel",
+ "field_path": "show_in_command_panel",
+ "label": "Command panel",
+ "description": "Whether the step appears in the command panel.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow_step",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow_step.auto_archive_after_hours",
+ "field_path": "auto_archive_after_hours",
+ "label": "Auto archive",
+ "description": "Hours before tasks in this step are archived.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow_step",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow_step.agent_profile_id",
+ "field_path": "agent_profile_id",
+ "label": "Agent profile",
+ "description": "Profile bound to this step.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow_step",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow_step.profile_session_start_policy",
+ "field_path": "profile_session_start_policy",
+ "label": "Session start policy",
+ "description": "Session policy when entering a profile-bound step.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow_step",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow_step.profile_session_end_policy",
+ "field_path": "profile_session_end_policy",
+ "label": "Session end policy",
+ "description": "Session policy when leaving a profile-bound step.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow_step",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow_step.wip_limit",
+ "field_path": "wip_limit",
+ "label": "WIP limit",
+ "description": "Maximum admitted work in this step.",
+ "json_type": "integer",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow_step",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow_step.pull_from_step_id",
+ "field_path": "pull_from_step_id",
+ "label": "Pull source",
+ "description": "Step that supplies work to this step.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow_step",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow_step.stage_type",
+ "field_path": "stage_type",
+ "label": "Stage type",
+ "description": "Workflow stage type.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow_step",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow_step.auto_advance_requires_signal",
+ "field_path": "auto_advance_requires_signal",
+ "label": "Completion signal",
+ "description": "Require an explicit completion signal before advancing.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow_step",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workflow_step.cancel_triggers_turn_complete",
+ "field_path": "cancel_triggers_turn_complete",
+ "label": "Cancel transition",
+ "description": "Whether cancellation runs turn-complete actions.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workflow",
+ "writable": true,
+ "validator": "workflow.workflow_step",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "workflow.workflow_step.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ },
+ {
+ "domain": "workspaces",
+ "resource_type": "workspace",
+ "label": "Workspaces",
+ "description": "Workspace defaults and display settings.",
+ "owner": "workspace",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true
+ },
+ "fields": [
+ {
+ "key": "workspace.name",
+ "field_path": "name",
+ "label": "Name",
+ "description": "Workspace name.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.workspace",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workspace.description",
+ "field_path": "description",
+ "label": "Description",
+ "description": "Workspace description.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.workspace",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workspace.default_executor_id",
+ "field_path": "default_executor_id",
+ "label": "Default executor",
+ "description": "Default execution target.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.workspace",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workspace.default_environment_id",
+ "field_path": "default_environment_id",
+ "label": "Default environment",
+ "description": "Default runtime environment.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.workspace",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workspace.default_agent_profile_id",
+ "field_path": "default_agent_profile_id",
+ "label": "Default agent profile",
+ "description": "Default profile for new work.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.workspace",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ },
+ {
+ "key": "workspace.default_config_agent_profile_id",
+ "field_path": "default_config_agent_profile_id",
+ "label": "Default configuration profile",
+ "description": "Profile used for configuration work.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "workspace",
+ "writable": true,
+ "validator": "workspace.workspace",
+ "authority": "workspace.manage",
+ "settings_href": "/settings"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "workspace.workspace.update",
+ "authority": "workspace.manage"
+ }
+ ],
+ "settings_href": "/settings"
+ }
+ ],
+ "mutable_fields": {
+ "agent_profile": [
+ "allow_indexing",
+ "auto_approve",
+ "auto_fallback",
+ "cli_flags",
+ "cli_passthrough",
+ "command_prefix",
+ "config_options",
+ "dynamic",
+ "enabled",
+ "env_vars",
+ "fallback_model",
+ "mode",
+ "model",
+ "name"
+ ],
+ "user_settings": [
+ "agent_generated_task_titles",
+ "app_status_bar_enabled",
+ "app_status_bar_order",
+ "azure_devops_browse_preferences",
+ "changes_panel_layout",
+ "chat_submit_key",
+ "confirm_task_archive",
+ "default_editor_id",
+ "default_utility_agent_id",
+ "default_utility_agent_profile_id",
+ "default_utility_model",
+ "enable_preview_on_click",
+ "github_default_query_presets",
+ "github_saved_presets",
+ "gitlab_saved_presets",
+ "initial_setup_complete",
+ "jira_saved_views",
+ "jira_task_presets",
+ "kanban_hidden_step_ids",
+ "kanban_view_mode",
+ "keyboard_shortcuts",
+ "last_seen_display",
+ "lsp_auto_install_languages",
+ "lsp_auto_start_languages",
+ "lsp_server_configs",
+ "lsp_status_location",
+ "mcp_task_agent_profile_default",
+ "preferred_shell",
+ "prevent_auto_start_agent_on_open",
+ "quick_chat_tab_order_by_workspace",
+ "release_notes_last_seen_version",
+ "repository_ids",
+ "resolve_session_hostnames",
+ "review_auto_mark_on_scroll",
+ "saved_layouts",
+ "show_anchored_prompt_bar",
+ "show_release_notification",
+ "show_scroll_to_last_prompt",
+ "show_scroll_to_start",
+ "show_todo_list_panel",
+ "show_todo_list_panel_only_when_not_empty",
+ "show_transcript_auto_scroll_control",
+ "sidebar_active_view_id",
+ "sidebar_draft",
+ "sidebar_task_color_automation",
+ "sidebar_task_color_patch",
+ "sidebar_task_colors",
+ "sidebar_task_prefs",
+ "sidebar_views",
+ "startup_page",
+ "system_metrics_display",
+ "task_create_last_used",
+ "tasks_list_group",
+ "tasks_list_show_details",
+ "tasks_list_sort",
+ "terminal_font_family",
+ "terminal_font_size",
+ "terminal_link_behavior",
+ "thread_active_view_id",
+ "thread_view_draft",
+ "thread_views",
+ "unread_divider",
+ "workflow_filter_id",
+ "workflow_ids_with_auto_hide_empty_steps",
+ "workspace_id"
+ ]
+ }
+}
diff --git a/apps/web/lib/settings-discovery/coverage-inventory.test.ts b/apps/web/lib/settings-discovery/coverage-inventory.test.ts
new file mode 100644
index 0000000000..7563f99fd9
--- /dev/null
+++ b/apps/web/lib/settings-discovery/coverage-inventory.test.ts
@@ -0,0 +1,85 @@
+import { describe, expect, it } from "vitest";
+import {
+ SETTINGS_COVERAGE_INVENTORY,
+ SETTINGS_COVERAGE_RESOURCE_TYPES,
+ validateSettingsCoverageInventory,
+ type SettingsCoverageEvidence,
+} from "./coverage-inventory";
+
+const REQUIRED_DOMAINS = [
+ "agent_profile",
+ "agent_profile_mcp",
+ "user_settings",
+ "workflow",
+ "workflow_step",
+ "workspace",
+ "repository",
+ "repository_set",
+ "repository_script",
+ "executor",
+ "executor_profile",
+ "environment",
+ "task",
+ "prompt",
+ "utility_agent",
+ "editor",
+ "notification_provider",
+ "issue_integrations",
+ "code_host_integrations",
+ "automation",
+ "runtime_flag",
+ "storage_maintenance",
+] as const;
+
+describe("settings coverage inventory", () => {
+ it("records every required domain independently of the runtime catalog", () => {
+ const evidence = SETTINGS_COVERAGE_INVENTORY.map((entry) => entry.domain);
+
+ expect(evidence).toEqual(expect.arrayContaining([...REQUIRED_DOMAINS]));
+ expect(new Set(evidence).size).toBeGreaterThanOrEqual(REQUIRED_DOMAINS.length);
+ expect(SETTINGS_COVERAGE_INVENTORY.every((entry) => entry.sourcePaths.length > 0)).toBe(true);
+ });
+
+ it("rejects eligible fields that have no owner or remain pending", () => {
+ const invalid: SettingsCoverageEvidence[] = [
+ {
+ id: "missing-owner",
+ domain: "workspace",
+ fieldPath: "name",
+ sourcePaths: ["apps/web/components/settings/workspaces"],
+ status: "supported",
+ owner: "",
+ },
+ {
+ id: "pending-field",
+ domain: "workspace",
+ fieldPath: "default_executor_id",
+ sourcePaths: ["apps/backend/internal/task/service"],
+ status: "pending",
+ owner: "task-07-workspace-settings",
+ },
+ ];
+
+ expect(validateSettingsCoverageInventory(invalid)).toEqual([
+ "missing-owner: owner is required",
+ "pending-field: eligible fields cannot remain pending",
+ ]);
+ });
+
+ it("keeps explicit exceptions reasoned and recoverable", () => {
+ const exceptions = SETTINGS_COVERAGE_INVENTORY.filter((entry) => entry.status === "exception");
+
+ expect(exceptions.length).toBeGreaterThan(0);
+ expect(
+ exceptions.every((entry) => entry.exceptionCategory && entry.reason && entry.recovery),
+ ).toBe(true);
+ });
+
+ it("maps every catalog resource type to an independent coverage domain", async () => {
+ const contract = await import("./contract.generated.json");
+ const mapped = new Set(Object.values(SETTINGS_COVERAGE_RESOURCE_TYPES).flat());
+ for (const domain of contract.default.domains) {
+ expect(mapped.has(domain.resource_type), domain.resource_type).toBe(true);
+ }
+ });
+});
diff --git a/apps/web/lib/settings-discovery/coverage-inventory.ts b/apps/web/lib/settings-discovery/coverage-inventory.ts
new file mode 100644
index 0000000000..c70c49b0a3
--- /dev/null
+++ b/apps/web/lib/settings-discovery/coverage-inventory.ts
@@ -0,0 +1,628 @@
+import contract from "./contract.generated.json";
+
+export type SettingsCoverageStatus = "supported" | "exception" | "pending";
+
+export type SettingsExceptionCategory =
+ | "client-local"
+ | "read-only"
+ | "interactive-only"
+ | "action"
+ | "deployment-owned"
+ | "plugin-owned"
+ | "separate-product-contract";
+
+export type SettingsCoverageEvidence = {
+ id: string;
+ domain: string;
+ fieldPath: string;
+ sourcePaths: string[];
+ status: SettingsCoverageStatus;
+ owner: string;
+ exceptionCategory?: SettingsExceptionCategory;
+ reason?: string;
+ recovery?: string;
+};
+
+// i18n-exempt: settings coverage resource identifiers are protocol metadata, not UI copy.
+export const SETTINGS_COVERAGE_RESOURCE_TYPES: Readonly> = {
+ agents: ["agent"],
+ profiles: ["agent_profile", "agent_profile_mcp"],
+ user_preferences: ["user_settings"],
+ workflows: ["workflow", "workflow_step"],
+ workspaces: ["workspace", "repository", "repository_set", "repository_script"],
+ execution: ["executor", "executor_profile", "environment"],
+ tasks: ["task"],
+ prompts: ["prompt"],
+ utilities: ["utility_agent"],
+ editors: ["editor"],
+ notifications: ["notification_provider"],
+ issue_integrations: [
+ "issue_integration",
+ "jira_settings",
+ "jira_issue_watch",
+ "linear_settings",
+ "linear_issue_watch",
+ "sentry_instance",
+ "sentry_issue_watch",
+ ],
+ code_host_integrations: [
+ "code_host_integration",
+ "github_settings",
+ "github_review_watch",
+ "github_issue_watch",
+ "gitlab_settings",
+ "gitlab_review_watch",
+ "gitlab_issue_watch",
+ "azure_devops_settings",
+ "azure_devops_work_item_watch",
+ "azure_devops_pull_request_watch",
+ ],
+ automation: ["automation", "automation_trigger"],
+ runtime: ["runtime_flag"],
+ storage: ["storage_maintenance"],
+};
+
+const source = (...paths: string[]) => paths;
+
+const PROFILE_TASK = "task-01-profile-contract";
+const PROFILE_CRUD_SOURCE = "apps/backend/internal/agent/settings/controller/profile_crud.go";
+const PROFILE_DTO_SOURCE = "apps/backend/internal/agent/settings/dto/dto.go";
+const USER_TASK = "task-05-user-preferences";
+const USER_DTO_SOURCE = "apps/backend/internal/user/dto/dto.go";
+const WORKFLOW_TASK = "task-06-workflow-settings";
+const WORKSPACE_TASK = "task-07-workspace-settings";
+const WORKSPACE_SETTINGS_SOURCE =
+ "apps/web/components/settings/workspaces/workspace-settings-shell.tsx";
+const TASK_REQUESTS_SOURCE = "apps/backend/internal/task/service/service_requests.go";
+
+const supported = (
+ id: string,
+ domain: string,
+ fieldPath: string,
+ sourcePaths: string[],
+ owner: string,
+): SettingsCoverageEvidence => ({
+ id,
+ domain,
+ fieldPath,
+ sourcePaths,
+ status: "supported",
+ owner,
+});
+
+type SettingsExceptionInput = {
+ id: string;
+ domain: string;
+ fieldPath: string;
+ category: SettingsExceptionCategory;
+ reason: string;
+ recovery: string;
+ sourcePaths: string[];
+};
+
+const exception = ({
+ id,
+ domain,
+ fieldPath,
+ category,
+ reason,
+ recovery,
+ sourcePaths,
+}: SettingsExceptionInput): SettingsCoverageEvidence => ({
+ id,
+ domain,
+ fieldPath,
+ sourcePaths,
+ status: "exception",
+ owner: "explicit-exception",
+ exceptionCategory: category,
+ reason,
+ recovery,
+});
+
+// This list is intentionally maintained from UI and domain inputs rather than
+// generated from the runtime catalog. The adapter slices in this change bind
+// each listed eligible control to the compact settings contract.
+const UI_SETTINGS_COVERAGE_INVENTORY: SettingsCoverageEvidence[] = [
+ supported(
+ "agent-definition-fields",
+ "agents",
+ "settings",
+ source(
+ "apps/web/components/settings/agents",
+ "apps/backend/internal/agent/settings/controller",
+ ),
+ "task-01-profile-contract",
+ ),
+ supported(
+ "agent-profile-name",
+ "agent_profile",
+ "name",
+ source(
+ "apps/web/components/settings/profile-edit/profile-details-card.tsx",
+ PROFILE_CRUD_SOURCE,
+ ),
+ PROFILE_TASK,
+ ),
+ supported(
+ "agent-profile-model",
+ "agent_profile",
+ "model",
+ source("apps/web/components/settings/profile-model-fields.tsx", PROFILE_CRUD_SOURCE),
+ PROFILE_TASK,
+ ),
+ supported(
+ "agent-profile-fallback-model",
+ "agent_profile",
+ "fallback_model",
+ source("apps/web/components/settings/profile-model-config.ts", PROFILE_CRUD_SOURCE),
+ PROFILE_TASK,
+ ),
+ supported(
+ "agent-profile-auto-fallback",
+ "agent_profile",
+ "auto_fallback",
+ source("apps/web/components/settings/profile-model-config.ts", PROFILE_CRUD_SOURCE),
+ PROFILE_TASK,
+ ),
+ supported(
+ "agent-profile-mode",
+ "agent_profile",
+ "mode",
+ source("apps/web/components/settings/profile-form-fields.tsx", PROFILE_DTO_SOURCE),
+ PROFILE_TASK,
+ ),
+ supported(
+ "agent-profile-config-options",
+ "agent_profile",
+ "config_options",
+ source(
+ "apps/web/components/settings/profile-advanced-options.tsx",
+ "apps/backend/internal/agent/settings/profileconfig/profileconfig.go",
+ ),
+ PROFILE_TASK,
+ ),
+ supported(
+ "agent-profile-cli-flags",
+ "agent_profile",
+ "cli_flags",
+ source("apps/web/components/settings/cli-flags-field.tsx", PROFILE_DTO_SOURCE),
+ PROFILE_TASK,
+ ),
+ supported(
+ "agent-profile-environment-variables",
+ "agent_profile",
+ "env_vars",
+ source("apps/web/components/settings/profile-edit/env-vars-card.tsx", PROFILE_DTO_SOURCE),
+ PROFILE_TASK,
+ ),
+ supported(
+ "agent-profile-command-prefix",
+ "agent_profile",
+ "command_prefix",
+ source("apps/web/components/settings/command-prefix-field.tsx", PROFILE_CRUD_SOURCE),
+ PROFILE_TASK,
+ ),
+ supported(
+ "agent-profile-mcp-document",
+ "agent_profile_mcp",
+ "servers",
+ source(
+ "apps/web/app/settings/agents/[agentId]/profile-mcp-config-card.tsx",
+ "apps/backend/internal/agent/mcpconfig/service.go",
+ ),
+ "task-02-profile-mutations",
+ ),
+ supported(
+ "user-settings-task-behavior",
+ "user_settings",
+ "confirm_task_archive",
+ source("apps/web/components/settings/task-behavior-settings.tsx", USER_DTO_SOURCE),
+ USER_TASK,
+ ),
+ supported(
+ "user-settings-keyboard-shortcuts",
+ "user_settings",
+ "keyboard_shortcuts",
+ source("apps/web/components/settings/keyboard-shortcuts-card.tsx", USER_DTO_SOURCE),
+ USER_TASK,
+ ),
+ supported(
+ "user-settings-terminal",
+ "user_settings",
+ "terminal_font_size",
+ source("apps/web/components/settings/terminal-editors-settings.tsx", USER_DTO_SOURCE),
+ USER_TASK,
+ ),
+ supported(
+ "user-settings-saved-layouts",
+ "user_settings",
+ "saved_layouts",
+ source("apps/web/components/settings/layouts/layout-settings.tsx", USER_DTO_SOURCE),
+ USER_TASK,
+ ),
+ supported(
+ "user-settings-utility-defaults",
+ "user_settings",
+ "default_utility_model",
+ source("apps/web/components/settings/utility-agents-settings.tsx", USER_DTO_SOURCE),
+ USER_TASK,
+ ),
+ supported(
+ "workflow-name",
+ "workflow",
+ "name",
+ source(WORKSPACE_SETTINGS_SOURCE, "apps/backend/internal/workflow/service"),
+ WORKFLOW_TASK,
+ ),
+ supported(
+ "workflow-description",
+ "workflow",
+ "description",
+ source(WORKSPACE_SETTINGS_SOURCE, "apps/backend/internal/workflow/service"),
+ WORKFLOW_TASK,
+ ),
+ supported(
+ "workflow-step-fields",
+ "workflow_step",
+ "settings",
+ source(
+ "apps/web/components/settings/workflow-step-settings.tsx",
+ "apps/backend/internal/mcp/handlers/config_workflow_handlers.go",
+ ),
+ WORKFLOW_TASK,
+ ),
+ supported(
+ "workspace-name",
+ "workspace",
+ "name",
+ source(WORKSPACE_SETTINGS_SOURCE, "apps/backend/internal/task/service/service_resources.go"),
+ WORKSPACE_TASK,
+ ),
+ supported(
+ "workspace-default-executor",
+ "workspace",
+ "default_executor_id",
+ source(WORKSPACE_SETTINGS_SOURCE, TASK_REQUESTS_SOURCE),
+ WORKSPACE_TASK,
+ ),
+ supported(
+ "workspace-default-agent-profile",
+ "workspace",
+ "default_agent_profile_id",
+ source(WORKSPACE_SETTINGS_SOURCE, TASK_REQUESTS_SOURCE),
+ WORKSPACE_TASK,
+ ),
+ supported(
+ "repository-fields",
+ "repository",
+ "settings",
+ source("apps/web/components/settings/repository-card.tsx", TASK_REQUESTS_SOURCE),
+ WORKSPACE_TASK,
+ ),
+ supported(
+ "repository-set-fields",
+ "repository_set",
+ "settings",
+ source(
+ "apps/web/components/settings/repository-set-card.tsx",
+ "apps/backend/internal/task/service",
+ ),
+ WORKSPACE_TASK,
+ ),
+ supported(
+ "repository-script-fields",
+ "repository_script",
+ "settings",
+ source(
+ "apps/web/components/settings/repository-custom-scripts.tsx",
+ "apps/backend/internal/scriptengine",
+ ),
+ WORKSPACE_TASK,
+ ),
+ supported(
+ "executor-fields",
+ "executor",
+ "settings",
+ source("apps/web/components/settings/executor-profile-dialog.tsx", TASK_REQUESTS_SOURCE),
+ "task-08-executor-settings",
+ ),
+ supported(
+ "executor-profile-fields",
+ "executor_profile",
+ "settings",
+ source(
+ "apps/web/components/settings/profile-edit/profile-details-card.tsx",
+ TASK_REQUESTS_SOURCE,
+ ),
+ "task-08-executor-settings",
+ ),
+ supported(
+ "executor-environment-fields",
+ "environment",
+ "settings",
+ source(
+ "apps/web/components/settings/profile-edit/env-vars-card.tsx",
+ "apps/backend/internal/task/models",
+ ),
+ "task-08-executor-settings",
+ ),
+ supported(
+ "task-settings-fields",
+ "task",
+ "settings",
+ source(
+ "apps/web/components/settings/task-behavior-settings.tsx",
+ "apps/backend/internal/mcp/handlers/config_task_handlers.go",
+ ),
+ "task-09-task-settings",
+ ),
+ supported(
+ "saved-prompt-name",
+ "prompt",
+ "name",
+ source(
+ "apps/web/components/settings/prompts-settings.tsx",
+ "apps/backend/internal/prompts/models",
+ ),
+ "task-10-prompt-settings",
+ ),
+ supported(
+ "saved-prompt-content",
+ "prompt",
+ "content",
+ source(
+ "apps/web/components/settings/settings-prompt-editor.tsx",
+ "apps/backend/internal/prompts/service",
+ ),
+ "task-10-prompt-settings",
+ ),
+ supported(
+ "utility-agent-fields",
+ "utility_agent",
+ "settings",
+ source(
+ "apps/web/components/settings/utility-agents-settings.tsx",
+ "apps/backend/internal/utility/service",
+ ),
+ "task-11-utility-settings",
+ ),
+ supported(
+ "editor-definition-fields",
+ "editor",
+ "settings",
+ source(
+ "apps/web/components/settings/editors-settings.tsx",
+ "apps/backend/internal/editors/service",
+ ),
+ "task-12-editor-settings",
+ ),
+ supported(
+ "notification-provider-fields",
+ "notification_provider",
+ "settings",
+ source(
+ "apps/web/components/settings/notifications-settings.tsx",
+ "apps/backend/internal/notifications/service",
+ ),
+ "task-13-notification-settings",
+ ),
+ supported(
+ "issue-integration-fields",
+ "issue_integrations",
+ "settings",
+ source(
+ "apps/web/components/settings/integrations",
+ "apps/backend/internal/jira",
+ "apps/backend/internal/linear",
+ ),
+ "task-14-issue-integration-settings",
+ ),
+ supported(
+ "code-host-integration-fields",
+ "code_host_integrations",
+ "settings",
+ source(
+ "apps/web/components/settings/integrations",
+ "apps/backend/internal/github",
+ "apps/backend/internal/gitlab",
+ "apps/backend/internal/azuredevops",
+ ),
+ "task-15-codehost-settings",
+ ),
+ supported(
+ "automation-fields",
+ "automation",
+ "settings",
+ source("apps/web/app/settings/workspace/[id]/automations", "apps/backend/internal/automation"),
+ "task-16-automation-settings",
+ ),
+ supported(
+ "runtime-flag-override",
+ "runtime_flag",
+ "override",
+ source(
+ "apps/web/components/settings/system/feature-toggles-route.tsx",
+ "apps/backend/internal/runtimeflags/registry.go",
+ ),
+ "task-17-runtime-settings",
+ ),
+ supported(
+ "storage-maintenance-settings",
+ "storage_maintenance",
+ "settings",
+ source(
+ "apps/web/components/settings/system/storage/storage-maintenance-settings.tsx",
+ "apps/backend/internal/system/storage/settings.go",
+ ),
+ "task-18-storage-settings",
+ ),
+ // i18n-exempt: settings discovery metadata is consumed by agents, not rendered UI.
+ exception({
+ id: "user-settings-pane-size",
+ domain: "user_settings",
+ fieldPath: "pane_sizes",
+ category: "client-local",
+ reason: "Stored in the browser layout owner.",
+ recovery: "Use the local Settings control on this device.",
+ sourcePaths: source("apps/web/components/settings/layouts/layout-settings.tsx"),
+ }),
+ // i18n-exempt: settings discovery metadata is consumed by agents, not rendered UI.
+ exception({
+ id: "startup-yaml",
+ domain: "startup_configuration",
+ fieldPath: "config.yaml",
+ category: "deployment-owned",
+ reason: "Startup configuration belongs to the deployment source catalog.",
+ recovery: "Edit the deployment configuration and restart through the operator workflow.",
+ sourcePaths: source("apps/backend/internal/common/config/catalog.go"),
+ }),
+ // i18n-exempt: settings discovery metadata is consumed by agents, not rendered UI.
+ exception({
+ id: "credential-enrollment",
+ domain: "integration_credentials",
+ fieldPath: "credentials",
+ category: "interactive-only",
+ reason: "Credential enrollment requires the provider authorization flow.",
+ recovery: "Use the integration connection flow in Settings.",
+ sourcePaths: source("apps/web/components/settings/integrations"),
+ }),
+ // i18n-exempt: settings discovery metadata is consumed by agents, not rendered UI.
+ exception({
+ id: "plugin-settings",
+ domain: "plugin",
+ fieldPath: "settings",
+ category: "plugin-owned",
+ reason: "Plugin settings are owned by the installed plugin.",
+ recovery: "Open the plugin-owned Settings page.",
+ sourcePaths: source("apps/web/components/settings/plugins"),
+ }),
+ // i18n-exempt: settings discovery metadata is consumed by agents, not rendered UI.
+ exception({
+ id: "runtime-health",
+ domain: "runtime",
+ fieldPath: "health",
+ category: "read-only",
+ reason: "Runtime health is computed state, not saved configuration.",
+ recovery: "Use the System Status page.",
+ sourcePaths: source("apps/web/components/settings/system"),
+ }),
+ // i18n-exempt: settings discovery metadata is consumed by agents, not rendered UI.
+ exception({
+ id: "workflow-reorder",
+ domain: "workflow",
+ fieldPath: "position",
+ category: "action",
+ reason: "Reordering is an explicit lifecycle operation.",
+ recovery: "Use the workflow reorder action.",
+ sourcePaths: source("apps/backend/internal/mcp/server/config_handlers.go"),
+ }),
+ // i18n-exempt: settings discovery metadata is consumed by agents, not rendered UI.
+ exception({
+ id: "office-organization",
+ domain: "office",
+ fieldPath: "organization",
+ category: "separate-product-contract",
+ reason: "Office organization management has its own contract.",
+ recovery: "Use the Office organization surface.",
+ sourcePaths: source("apps/backend/internal/office"),
+ }),
+];
+
+const ACTUAL_MUTABLE_FIELD_SOURCES: Record = {
+ agent_profile: {
+ sourcePaths: [PROFILE_DTO_SOURCE, PROFILE_CRUD_SOURCE],
+ owner: PROFILE_TASK,
+ },
+ user_settings: {
+ sourcePaths: [USER_DTO_SOURCE, "apps/backend/internal/user/controller/controller.go"],
+ owner: USER_TASK,
+ },
+};
+
+const actualMutableFields = (
+ contract as typeof contract & {
+ mutable_fields?: Record;
+ }
+).mutable_fields;
+const generatedMutableCoverage: SettingsCoverageEvidence[] = Object.entries(
+ actualMutableFields ?? {},
+).flatMap(([resourceType, fieldPaths]) => {
+ const sourceInfo = ACTUAL_MUTABLE_FIELD_SOURCES[resourceType];
+ if (!sourceInfo) return [];
+ return fieldPaths.map((fieldPath) =>
+ supported(
+ `dto-contract-${resourceType}-${fieldPath}`,
+ resourceType,
+ fieldPath,
+ sourceInfo.sourcePaths,
+ sourceInfo.owner,
+ ),
+ );
+});
+
+export const SETTINGS_COVERAGE_INVENTORY: SettingsCoverageEvidence[] = [
+ ...UI_SETTINGS_COVERAGE_INVENTORY,
+ ...generatedMutableCoverage.filter(
+ (generated) =>
+ !UI_SETTINGS_COVERAGE_INVENTORY.some(
+ (existing) =>
+ existing.domain === generated.domain && existing.fieldPath === generated.fieldPath,
+ ),
+ ),
+];
+
+type SettingsContractDomain = {
+ resource_type: string;
+ fields: Array<{ field_path: string; support: string; writable?: boolean }>;
+};
+
+export function validateMutableFieldParity(
+ actualFields: Record,
+ domains: SettingsContractDomain[],
+): string[] {
+ const errors: string[] = [];
+ for (const [resourceType, fields] of Object.entries(actualFields)) {
+ const domain = domains.find((candidate) => candidate.resource_type === resourceType);
+ if (!domain) {
+ errors.push(`${resourceType}: mutable DTO has no catalog domain`);
+ continue;
+ }
+ const catalogFields = new Set(
+ domain.fields
+ .filter((field) => field.support === "supported" && field.writable)
+ .map((field) => field.field_path),
+ );
+ for (const fieldPath of fields) {
+ if (!catalogFields.has(fieldPath)) {
+ errors.push(`${resourceType}.${fieldPath}: mutable DTO field is missing from catalog`);
+ }
+ }
+ for (const fieldPath of catalogFields) {
+ if (!fields.includes(fieldPath)) {
+ errors.push(`${resourceType}.${fieldPath}: catalog field is missing from mutable DTO`);
+ }
+ }
+ }
+ return errors;
+}
+
+export function validateSettingsCoverageInventory(entries: SettingsCoverageEvidence[]): string[] {
+ const errors: string[] = [];
+ for (const entry of entries) {
+ if (!entry.owner.trim()) errors.push(`${entry.id}: owner is required`);
+ if (entry.status === "pending") {
+ errors.push(`${entry.id}: eligible fields cannot remain pending`);
+ }
+ if (entry.status === "exception") {
+ if (!entry.exceptionCategory) errors.push(`${entry.id}: exception category is required`);
+ if (!entry.reason?.trim()) errors.push(`${entry.id}: exception reason is required`);
+ if (!entry.recovery?.trim()) errors.push(`${entry.id}: exception recovery is required`);
+ }
+ }
+ return errors;
+}
+
+export const SETTINGS_COVERAGE_DOMAIN_COUNT = new Set(
+ SETTINGS_COVERAGE_INVENTORY.map((entry) => entry.domain),
+).size;
diff --git a/apps/web/lib/settings-discovery/delivery-coverage.test.ts b/apps/web/lib/settings-discovery/delivery-coverage.test.ts
new file mode 100644
index 0000000000..7b33f84327
--- /dev/null
+++ b/apps/web/lib/settings-discovery/delivery-coverage.test.ts
@@ -0,0 +1,84 @@
+import { describe, expect, it } from "vitest";
+import {
+ SETTINGS_COVERAGE_INVENTORY,
+ SETTINGS_COVERAGE_RESOURCE_TYPES,
+ validateMutableFieldParity,
+ validateSettingsCoverageInventory,
+} from "./coverage-inventory";
+import contract from "./contract.generated.json";
+
+describe("settings delivery coverage", () => {
+ it("has no pending eligible inventory entries", () => {
+ expect(validateSettingsCoverageInventory(SETTINGS_COVERAGE_INVENTORY)).toEqual([]);
+ expect(SETTINGS_COVERAGE_INVENTORY.some((entry) => entry.status === "supported")).toBe(true);
+ });
+
+ it("keeps every inventory entry independently traceable", () => {
+ const ids = SETTINGS_COVERAGE_INVENTORY.map((entry) => entry.id);
+ expect(new Set(ids).size).toBe(ids.length);
+ expect(
+ SETTINGS_COVERAGE_INVENTORY.every(
+ (entry) => entry.owner.length > 0 && entry.sourcePaths.length > 0,
+ ),
+ ).toBe(true);
+ });
+
+ it("keeps integration and automation coverage mapped to concrete resources", () => {
+ const catalogTypes = new Set(contract.domains.map((domain) => domain.resource_type));
+ for (const resourceTypes of Object.values(SETTINGS_COVERAGE_RESOURCE_TYPES)) {
+ for (const resourceType of resourceTypes) {
+ expect(catalogTypes.has(resourceType), resourceType).toBe(true);
+ }
+ }
+ });
+
+ it("compares catalog fields with independently reflected mutable DTO fields", () => {
+ const mutableFields = (
+ contract as typeof contract & {
+ mutable_fields?: Record;
+ }
+ ).mutable_fields;
+ expect(mutableFields).toBeDefined();
+
+ expect(validateMutableFieldParity(mutableFields ?? {}, contract.domains)).toEqual([]);
+ for (const resourceType of ["agent_profile", "user_settings"]) {
+ for (const fieldPath of mutableFields?.[resourceType] ?? []) {
+ expect(
+ SETTINGS_COVERAGE_INVENTORY.some(
+ (entry) => entry.domain === resourceType && entry.fieldPath === fieldPath,
+ ),
+ `${resourceType}.${fieldPath} missing from coverage inventory`,
+ ).toBe(true);
+ }
+ }
+ });
+
+ it("detects added DTO fields and removed catalog descriptors", () => {
+ const mutableFields = (
+ contract as typeof contract & {
+ mutable_fields: Record;
+ }
+ ).mutable_fields;
+ const userDomain = contract.domains.find((item) => item.resource_type === "user_settings");
+ expect(userDomain).toBeDefined();
+ const addedField = {
+ ...mutableFields,
+ user_settings: [...mutableFields.user_settings, "future_mutable_field"],
+ };
+ expect(validateMutableFieldParity(addedField, contract.domains)).toContain(
+ "user_settings.future_mutable_field: mutable DTO field is missing from catalog",
+ );
+
+ const catalogWithoutDescriptor = contract.domains.map((domain) =>
+ domain.resource_type === "user_settings"
+ ? {
+ ...domain,
+ fields: domain.fields.filter((field) => field.field_path !== "keyboard_shortcuts"),
+ }
+ : domain,
+ );
+ expect(validateMutableFieldParity(mutableFields, catalogWithoutDescriptor)).toContain(
+ "user_settings.keyboard_shortcuts: mutable DTO field is missing from catalog",
+ );
+ });
+});
diff --git a/apps/web/lib/settings-discovery/profile-contract.generated.json b/apps/web/lib/settings-discovery/profile-contract.generated.json
new file mode 100644
index 0000000000..221adcff2f
--- /dev/null
+++ b/apps/web/lib/settings-discovery/profile-contract.generated.json
@@ -0,0 +1,390 @@
+{
+ "schema_version": "settings-catalog.v1",
+ "generated_by": "cmd/settings-catalog",
+ "domains": [
+ {
+ "domain": "profiles",
+ "resource_type": "agent_profile",
+ "label": "Agent profiles",
+ "description": "Saved agent profile settings used for future sessions.",
+ "owner": "agent-settings",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true,
+ "allows_workspace_id": true
+ },
+ "fields": [
+ {
+ "key": "agent_profile.name",
+ "field_path": "name",
+ "label": "name",
+ "description": "Profile display name.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.model",
+ "field_path": "model",
+ "label": "model",
+ "description": "Preferred model; empty uses the agent default.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.fallback_model",
+ "field_path": "fallback_model",
+ "label": "fallback_model",
+ "description": "Optional fallback model.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.auto_fallback",
+ "field_path": "auto_fallback",
+ "label": "auto_fallback",
+ "description": "Enable automatic fallback behavior.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.mode",
+ "field_path": "mode",
+ "label": "mode",
+ "description": "Agent operating mode.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.config_options",
+ "field_path": "config_options",
+ "label": "config_options",
+ "description": "Typed provider configuration options.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "replacement": true,
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.allow_indexing",
+ "field_path": "allow_indexing",
+ "label": "allow_indexing",
+ "description": "Legacy indexing permission field.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.auto_approve",
+ "field_path": "auto_approve",
+ "label": "auto_approve",
+ "description": "Automatically approve agent permissions.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.cli_passthrough",
+ "field_path": "cli_passthrough",
+ "label": "cli_passthrough",
+ "description": "Allow CLI passthrough mode.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.enabled",
+ "field_path": "enabled",
+ "label": "enabled",
+ "description": "Allow this profile for new work.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.cli_flags",
+ "field_path": "cli_flags",
+ "label": "cli_flags",
+ "description": "Complete replacement list of CLI flags.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "replacement": true,
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.env_vars",
+ "field_path": "env_vars",
+ "label": "env_vars",
+ "description": "Complete replacement list of environment variables.",
+ "json_type": "array",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "sensitive": true,
+ "replacement": true,
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.command_prefix",
+ "field_path": "command_prefix",
+ "label": "command_prefix",
+ "description": "Optional launcher command prefix.",
+ "json_type": "string",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ },
+ {
+ "key": "agent_profile.dynamic",
+ "field_path": "dynamic",
+ "label": "dynamic",
+ "description": "Versioned dynamic routing document.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile",
+ "authority": "org.config.manage",
+ "replacement": true,
+ "change_timing": "future_sessions",
+ "settings_href": "/settings/agents"
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "agent-settings.profile.update",
+ "authority": "org.config.manage"
+ }
+ ],
+ "settings_href": "/settings/agents"
+ },
+ {
+ "domain": "profiles",
+ "resource_type": "agent_profile_mcp",
+ "label": "Profile MCP documents",
+ "description": "Separate MCP server settings for a saved agent profile.",
+ "owner": "agent-settings",
+ "scope": "resource",
+ "target": {
+ "scope": "resource",
+ "requires_resource_id": true
+ },
+ "fields": [
+ {
+ "key": "agent_profile_mcp.enabled",
+ "field_path": "enabled",
+ "label": "MCP enabled",
+ "description": "Enable the profile MCP document.",
+ "json_type": "boolean",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile-mcp",
+ "authority": "org.config.manage"
+ },
+ {
+ "key": "agent_profile_mcp.servers",
+ "field_path": "servers",
+ "label": "MCP servers",
+ "description": "Complete replacement map of validated MCP servers.",
+ "json_type": "object",
+ "support": "supported",
+ "classification": "writable",
+ "owner": "agent-settings",
+ "writable": true,
+ "validator": "agent-settings.profile-mcp",
+ "authority": "org.config.manage",
+ "sensitive": true,
+ "replacement": true
+ },
+ {
+ "key": "agent_profile_mcp.meta",
+ "field_path": "meta",
+ "label": "MCP metadata",
+ "description": "Preserved metadata from the MCP document.",
+ "json_type": "object",
+ "support": "read_only",
+ "classification": "computed",
+ "owner": "agent-settings",
+ "sensitive": true
+ }
+ ],
+ "operations": [
+ {
+ "name": "update",
+ "binding": "agent-settings.profile-mcp.update",
+ "authority": "org.config.manage"
+ }
+ ],
+ "settings_href": "/settings/agents"
+ }
+ ],
+ "mutable_fields": {
+ "agent_profile": [
+ "allow_indexing",
+ "auto_approve",
+ "auto_fallback",
+ "cli_flags",
+ "cli_passthrough",
+ "command_prefix",
+ "config_options",
+ "dynamic",
+ "enabled",
+ "env_vars",
+ "fallback_model",
+ "mode",
+ "model",
+ "name"
+ ],
+ "user_settings": [
+ "agent_generated_task_titles",
+ "app_status_bar_enabled",
+ "app_status_bar_order",
+ "azure_devops_browse_preferences",
+ "changes_panel_layout",
+ "chat_submit_key",
+ "confirm_task_archive",
+ "default_editor_id",
+ "default_utility_agent_id",
+ "default_utility_agent_profile_id",
+ "default_utility_model",
+ "enable_preview_on_click",
+ "github_default_query_presets",
+ "github_saved_presets",
+ "gitlab_saved_presets",
+ "initial_setup_complete",
+ "jira_saved_views",
+ "jira_task_presets",
+ "kanban_hidden_step_ids",
+ "kanban_view_mode",
+ "keyboard_shortcuts",
+ "last_seen_display",
+ "lsp_auto_install_languages",
+ "lsp_auto_start_languages",
+ "lsp_server_configs",
+ "lsp_status_location",
+ "mcp_task_agent_profile_default",
+ "preferred_shell",
+ "prevent_auto_start_agent_on_open",
+ "quick_chat_tab_order_by_workspace",
+ "release_notes_last_seen_version",
+ "repository_ids",
+ "resolve_session_hostnames",
+ "review_auto_mark_on_scroll",
+ "saved_layouts",
+ "show_anchored_prompt_bar",
+ "show_release_notification",
+ "show_scroll_to_last_prompt",
+ "show_scroll_to_start",
+ "show_todo_list_panel",
+ "show_todo_list_panel_only_when_not_empty",
+ "show_transcript_auto_scroll_control",
+ "sidebar_active_view_id",
+ "sidebar_draft",
+ "sidebar_task_color_automation",
+ "sidebar_task_color_patch",
+ "sidebar_task_colors",
+ "sidebar_task_prefs",
+ "sidebar_views",
+ "startup_page",
+ "system_metrics_display",
+ "task_create_last_used",
+ "tasks_list_group",
+ "tasks_list_show_details",
+ "tasks_list_sort",
+ "terminal_font_family",
+ "terminal_font_size",
+ "terminal_link_behavior",
+ "thread_active_view_id",
+ "thread_view_draft",
+ "thread_views",
+ "unread_divider",
+ "workflow_filter_id",
+ "workflow_ids_with_auto_hide_empty_steps",
+ "workspace_id"
+ ]
+ }
+}
diff --git a/apps/web/lib/settings-discovery/profile-contract.test.ts b/apps/web/lib/settings-discovery/profile-contract.test.ts
new file mode 100644
index 0000000000..2d68272973
--- /dev/null
+++ b/apps/web/lib/settings-discovery/profile-contract.test.ts
@@ -0,0 +1,28 @@
+import { describe, expect, it } from "vitest";
+import {
+ PROFILE_EDITABLE_FIELD_PATHS,
+ profileContractCovers,
+ profileContractField,
+ profileContractFields,
+} from "./profile-contract";
+
+describe("profile settings contract adapter", () => {
+ it("covers every editable profile field with generated metadata", () => {
+ const fields = profileContractFields();
+
+ expect(fields.map((field) => field.field_path)).toEqual([...PROFILE_EDITABLE_FIELD_PATHS]);
+ expect(fields.every((field) => field.support === "supported" && field.writable)).toBe(true);
+ });
+
+ it("keeps replacement and sensitive profile fields discoverable", () => {
+ expect(profileContractField("agent_profile", "config_options")?.replacement).toBe(true);
+ expect(profileContractField("agent_profile", "cli_flags")?.replacement).toBe(true);
+ expect(profileContractField("agent_profile", "env_vars")?.sensitive).toBe(true);
+ expect(profileContractField("agent_profile_mcp", "servers")?.sensitive).toBe(true);
+ });
+
+ it("does not turn provider-defined dynamic keys into catalog fields", () => {
+ expect(profileContractCovers("provider_specific_option")).toBe(false);
+ expect(profileContractField("agent_profile", "provider_specific_option")).toBeUndefined();
+ });
+});
diff --git a/apps/web/lib/settings-discovery/profile-contract.ts b/apps/web/lib/settings-discovery/profile-contract.ts
new file mode 100644
index 0000000000..4ff82da79f
--- /dev/null
+++ b/apps/web/lib/settings-discovery/profile-contract.ts
@@ -0,0 +1,55 @@
+import contract from "./profile-contract.generated.json";
+
+type ContractField = {
+ key: string;
+ field_path: string;
+ support: string;
+ writable?: boolean;
+ sensitive?: boolean;
+ replacement?: boolean;
+};
+
+type ContractDomain = {
+ resource_type: string;
+ fields: ContractField[];
+};
+
+const domains = contract.domains as ContractDomain[];
+
+export const PROFILE_EDITABLE_FIELD_PATHS = [
+ "name",
+ "model",
+ "fallback_model",
+ "auto_fallback",
+ "mode",
+ "config_options",
+ "allow_indexing",
+ "auto_approve",
+ "cli_passthrough",
+ "enabled",
+ "cli_flags",
+ "env_vars",
+ "command_prefix",
+ "dynamic",
+] as const;
+
+export type ProfileEditableFieldPath = (typeof PROFILE_EDITABLE_FIELD_PATHS)[number];
+
+export function profileContractField(
+ resourceType: "agent_profile" | "agent_profile_mcp",
+ fieldPath: string,
+): ContractField | undefined {
+ return domains
+ .find((domain) => domain.resource_type === resourceType)
+ ?.fields.find((field) => field.field_path === fieldPath);
+}
+
+export function profileContractFields(): ContractField[] {
+ return PROFILE_EDITABLE_FIELD_PATHS.map((fieldPath) =>
+ profileContractField("agent_profile", fieldPath),
+ ).filter((field): field is ContractField => field !== undefined);
+}
+
+export function profileContractCovers(fieldPath: string): fieldPath is ProfileEditableFieldPath {
+ return (PROFILE_EDITABLE_FIELD_PATHS as readonly string[]).includes(fieldPath);
+}
diff --git a/apps/web/lib/types/backend.ts b/apps/web/lib/types/backend.ts
index fc43bfb1cc..ecef25d4c1 100644
--- a/apps/web/lib/types/backend.ts
+++ b/apps/web/lib/types/backend.ts
@@ -154,6 +154,11 @@ export type AgentSettingsUpdatedPayload = {
agent: Agent;
};
+export type AgentProfileMcpConfigUpdatedPayload = {
+ profile_id: string;
+ workspace_id?: string | null;
+};
+
export type AgentAvailableUpdatedPayload = {
agents: AvailableAgent[];
tools?: ToolStatus[];
@@ -432,6 +437,10 @@ export type BackendMessageMap = SessionBackendMessageMap &
"task.plan.reverted": BackendMessage<"task.plan.reverted", TaskPlanRevisionEventPayload>;
"agent.updated": BackendMessage<"agent.updated", AgentUpdatePayload>;
"agent.settings.updated": BackendMessage<"agent.settings.updated", AgentSettingsUpdatedPayload>;
+ "agent.profile.mcp_config.updated": BackendMessage<
+ "agent.profile.mcp_config.updated",
+ AgentProfileMcpConfigUpdatedPayload
+ >;
"agent.available.updated": BackendMessage<
"agent.available.updated",
AgentAvailableUpdatedPayload
diff --git a/apps/web/src/locales/en/agents.json b/apps/web/src/locales/en/agents.json
index 0f800c0d0c..fab93657cd 100644
--- a/apps/web/src/locales/en/agents.json
+++ b/apps/web/src/locales/en/agents.json
@@ -165,6 +165,10 @@
"profileNameRequiredDescription": "Please enter a profile name before saving.",
"profileNameRequiredTitle": "Profile name is required",
"profileNotFound": "Profile not found.",
+ "profileExternalChangeTitle": "Profile changed elsewhere",
+ "profileExternalChangeDescription": "This profile changed while you were editing. Your draft is preserved. Discard it to load the latest saved values before saving again.",
+ "profileExternalChangeDiscard": "Load latest profile",
+ "profileExternalChangeInvalidReason": "Load the latest profile before saving.",
"profileSettings": "Profile settings",
"promptTokenHint": "<0>{{token}}0> will be replaced with your task description or follow-up message.",
"ptyConnectionError": "Connection error",
diff --git a/apps/web/src/locales/pseudo/agents.json b/apps/web/src/locales/pseudo/agents.json
index 4977eb60a9..8b43f30348 100644
--- a/apps/web/src/locales/pseudo/agents.json
+++ b/apps/web/src/locales/pseudo/agents.json
@@ -165,6 +165,10 @@
"profileNameRequiredDescription": "Ƥĺēàśē ēńţēŕ à ƥŕōƒĩĺē ńàḿē ƀēƒōŕē śàvĩńĝ.",
"profileNameRequiredTitle": "Ƥŕōƒĩĺē ńàḿē ĩś ŕēqũĩŕēď",
"profileNotFound": "Ƥŕōƒĩĺē ńōţ ƒōũńď.",
+ "profileExternalChangeTitle": "Ƥŕōƒĩĺē ćĥàńĝēď ēĺśēŵĥēŕē",
+ "profileExternalChangeDescription": "Ţĥĩś ƥŕōƒĩĺē ćĥàńĝēď ŵĥĩĺē ŷōũ ŵēŕē ēďĩţĩńĝ. Ŷōũŕ ďŕàƒţ ĩś ƥŕēśēŕvēď. Ďĩśćàŕď ĩţ ţō ĺōàď ţĥē ĺàţēśţ śàvēď vàĺũēś ƀēƒōŕē śàvĩńĝ àĝàĩń.",
+ "profileExternalChangeDiscard": "Ĺōàď ĺàţēśţ ƥŕōƒĩĺē",
+ "profileExternalChangeInvalidReason": "Ĺōàď ţĥē ĺàţēśţ ƥŕōƒĩĺē ƀēƒōŕē śàvĩńĝ.",
"profileSettings": "Ƥŕōƒĩĺē śēţţĩńĝś",
"promptTokenHint": "<0>{{token}}0> ŵĩĺĺ ƀē ŕēƥĺàćēď ŵĩţĥ ŷōũŕ ţàśķ ďēśćŕĩƥţĩōń ōŕ ƒōĺĺōŵ-ũƥ ḿēśśàĝē.",
"ptyConnectionError": "Ćōńńēćţĩōń ēŕŕōŕ",
diff --git a/apps/web/src/locales/pt-pt/agents.json b/apps/web/src/locales/pt-pt/agents.json
index d2828cb911..a62f49c7cb 100644
--- a/apps/web/src/locales/pt-pt/agents.json
+++ b/apps/web/src/locales/pt-pt/agents.json
@@ -153,6 +153,10 @@
"profileNameRequiredDescription": "Introduza um nome de perfil antes de guardar.",
"profileNameRequiredTitle": "O nome do perfil é obrigatório",
"profileNotFound": "Perfil não encontrado.",
+ "profileExternalChangeTitle": "O perfil foi alterado noutro local",
+ "profileExternalChangeDescription": "Este perfil foi alterado enquanto o editava. O seu rascunho foi preservado. Elimine-o para carregar os valores guardados mais recentes antes de guardar novamente.",
+ "profileExternalChangeDiscard": "Carregar o perfil mais recente",
+ "profileExternalChangeInvalidReason": "Carregue o perfil mais recente antes de guardar.",
"profileSettings": "Definições do perfil",
"promptTokenHint": "<0>{{token}}0> será substituído pela descrição da sua tarefa ou pela mensagem de seguimento.",
"ptyConnectionError": "Erro de ligação",
diff --git a/apps/web/src/locales/zh-cn/agents.json b/apps/web/src/locales/zh-cn/agents.json
index b365628c5b..b4602f51d2 100644
--- a/apps/web/src/locales/zh-cn/agents.json
+++ b/apps/web/src/locales/zh-cn/agents.json
@@ -162,6 +162,10 @@
"profileNameRequiredDescription": "保存前请输入配置名称。",
"profileNameRequiredTitle": "配置名称为必填项",
"profileNotFound": "未找到配置。",
+ "profileExternalChangeTitle": "配置已在其他位置更改",
+ "profileExternalChangeDescription": "你编辑时此配置已发生更改。你的草稿已保留。请放弃草稿以加载最新保存的值,然后再保存。",
+ "profileExternalChangeDiscard": "加载最新配置",
+ "profileExternalChangeInvalidReason": "请先加载最新配置,然后再保存。",
"profileSettings": "智能体配置",
"promptTokenHint": "<0>{{token}}0> 将替换为你的任务描述或后续消息。",
"ptyConnectionError": "连接错误",
diff --git a/apps/web/src/locales/zh-hk/agents.json b/apps/web/src/locales/zh-hk/agents.json
index 5f173f8e87..d6f5915191 100644
--- a/apps/web/src/locales/zh-hk/agents.json
+++ b/apps/web/src/locales/zh-hk/agents.json
@@ -162,6 +162,10 @@
"profileNameRequiredDescription": "儲存前請輸入設定名稱。",
"profileNameRequiredTitle": "設定名稱為必填項",
"profileNotFound": "未找到設定。",
+ "profileExternalChangeTitle": "設定檔已在其他位置變更",
+ "profileExternalChangeDescription": "你編輯時此設定檔已發生變更。你的草稿已保留。請放棄草稿以載入最新儲存值,然後再儲存。",
+ "profileExternalChangeDiscard": "載入最新設定檔",
+ "profileExternalChangeInvalidReason": "請先載入最新設定檔,然後再儲存。",
"profileSettings": "代理程式設定檔",
"promptTokenHint": "<0>{{token}}0> 將替換為你的任務描述或後續訊息。",
"ptyConnectionError": "連接錯誤",
diff --git a/apps/web/src/locales/zh-tw/agents.json b/apps/web/src/locales/zh-tw/agents.json
index 416c7c7014..082077b008 100644
--- a/apps/web/src/locales/zh-tw/agents.json
+++ b/apps/web/src/locales/zh-tw/agents.json
@@ -162,6 +162,10 @@
"profileNameRequiredDescription": "儲存前請輸入設定名稱。",
"profileNameRequiredTitle": "設定名稱為必填項",
"profileNotFound": "未找到設定。",
+ "profileExternalChangeTitle": "設定檔已在其他位置變更",
+ "profileExternalChangeDescription": "你編輯時此設定檔已發生變更。你的草稿已保留。請放棄草稿以載入最新儲存值,然後再儲存。",
+ "profileExternalChangeDiscard": "載入最新設定檔",
+ "profileExternalChangeInvalidReason": "請先載入最新設定檔,然後再儲存。",
"profileSettings": "代理程式設定檔",
"promptTokenHint": "<0>{{token}}0> 將替換為你的任務描述或後續訊息。",
"ptyConnectionError": "連線錯誤",
diff --git a/docs/decisions/2026-09-08-domain-owned-settings-catalog.md b/docs/decisions/2026-09-08-domain-owned-settings-catalog.md
new file mode 100644
index 0000000000..81d7db9188
--- /dev/null
+++ b/docs/decisions/2026-09-08-domain-owned-settings-catalog.md
@@ -0,0 +1,82 @@
+# ADR-2026-09-08-domain-owned-settings-catalog: Discover settings through domain-owned contracts
+
+**Status:** accepted
+**Date:** 2026-09-08
+**Area:** backend, frontend, protocol
+
+## Context
+
+The profile editor and MCP tools maintain different field lists.
+The frontend saves fields that the MCP schema and forwarding handlers cannot carry.
+Existing startup and navigation catalogs describe different contracts.
+
+The user selected searchable discovery, shared mutations, and parity tests as the direction for this work.
+Future settings domains need an ownership rule that preserves their existing validation and persistence.
+
+## Decision
+
+Platform owns a shared metadata contract for settings discovery.
+Each domain contributes descriptions and typed operation bindings while retaining ownership of values, defaults, validation, authorization, and persistence.
+The first implementation slice is the agent profile domain.
+The delivery scope also includes core user, workflow, workspace, repository, executor, task, prompt, utility, editor, notification, integration, automation, and system settings.
+The domain adoption design defines eligible fields and explicit exceptions. Profile parity alone does not complete this initiative.
+
+UI and MCP adapters use shared domain request contracts.
+The configuration assistant uses four compact settings tools: search, describe, read, and update.
+One additional bounded resource-lookup tool supplies authorized targets across domains.
+Common target selectors replace profile-specific arguments on the new generic tools.
+The catalog returns field schemas on demand. `update_settings_kandev` validates its `changes` object against the registered domain request before mutation.
+The outer tool schema contains no field enumeration or resource-schema union.
+Existing resource tools remain compatibility adapters. Resource creation, deletion, and import remain explicit lifecycle operations.
+Each field has a support status. An exception requires a reason and a destination or recovery description.
+
+The navigation catalog retains ownership of labels, translations, ordering, routes, and focus targets.
+Stable setting IDs connect navigation entries to domain metadata.
+Startup settings and runtime flags retain their current registries and source precedence.
+Their catalog adapters must derive metadata from those owners.
+Startup sources remain read-only. Runtime override writes retain environment locks and restart semantics.
+Authentication enablement and account authority remain outside generic mutation authority.
+
+Coverage checks compare independent editable contracts with catalog mappings.
+Tests that iterate only the catalog do not establish completeness.
+Transport tests also verify forwarding, persistence, errors, and notifications.
+Required CI checks cover registry completeness, generated contract freshness, and a curated search-query set.
+Coverage includes every built-in Settings control and independent editable domain contract.
+Client-local state, credential enrollment, plugin-owned settings, and explicit lifecycle actions receive reasoned classifications.
+An eligible field cannot pass delivery checks with a not-yet-supported classification.
+
+## Consequences
+
+Each adopter delivers complete coverage for a named domain.
+Discovery reports the adopted domains explicitly. It does not claim complete product coverage during adoption.
+The contract supports later file import/export without introducing another storage owner now.
+
+Adapters need tests for domain-specific defaults, dynamic choices, and permission boundaries.
+The UI remains hand-authored, and domain request contracts remain typed.
+Discovery metadata is advisory. Invocation always enforces current authority.
+Search results identify the setting, resource type, mutation field, support status, and match reason.
+The caller loads detailed schemas and context-dependent choices only for relevant settings.
+The backend selects schemas from trusted domain registrations. Agents cannot supply or modify a validation schema.
+
+Each domain switches its settings operations after parity checks pass. Unadopted legacy tools remain visible during implementation.
+The shared interface contains four settings tools and one resource-lookup tool. Explicit lifecycle and compatibility operations remain separate.
+Schemas grow in the registry, not in the generic tool definitions.
+Domain services validate resulting state and own any required transaction. An adapter-only lock cannot protect other writers.
+
+## Alternatives Considered
+
+- **One tool per setting:** This increases the tool surface and duplicates resource semantics across many handlers.
+- **One unrestricted settings map:** This hides scope, replacement rules, dependencies, and authorization behind arbitrary keys.
+- **Make a settings file authoritative first:** This introduces synchronization and precedence changes before it closes the interface gap.
+- **Use the navigation catalog as the backend schema:** Navigation entries include pages and controls that do not represent writable fields.
+- **Maintain manual MCP schemas indefinitely:** This preserves the source of the current field drift.
+- **Advertise every generated resource schema upfront:** This prevents field drift but increases context consumption as settings grow.
+
+## Related documents
+
+- [Requirements](../specs/platform/requirements/agent-settings-parity.md)
+- [System design](../specs/platform/system-design/agent-settings-parity.md)
+- [Domain adoption](../specs/platform/system-design/agent-settings-domains.md)
+- [Navigation boundaries](2026-08-04-navigation-manifest-boundaries.md)
+- [MCP tool profiles](2026-08-08-mcp-tool-profiles.md)
+- [Settings save coordinator](0046-settings-route-save-coordinator.md)
diff --git a/docs/decisions/INDEX.md b/docs/decisions/INDEX.md
index 0fbabf4e64..b4d7ee436e 100644
--- a/docs/decisions/INDEX.md
+++ b/docs/decisions/INDEX.md
@@ -259,4 +259,5 @@ Read individual ADRs for full context. Create new ones via `/record decision` or
| 2026-09-05-script-capable-html-preview-isolation | [Capability-Free Runtime for Script-Capable HTML Preview](2026-09-05-script-capable-html-preview-isolation.md) | proposed | frontend, desktop, security | 2026-09-05 |
| 2026-09-05-trusted-browser-html-preview | [Treat HTML Preview as Trusted Workspace Code](2026-09-05-trusted-browser-html-preview.md) | accepted | frontend, backend, agentctl, security | 2026-09-05 |
| 2026-09-07-activate-managed-runtime-defaults | [Activate Shipped Managed Runtime Defaults](2026-09-07-activate-managed-runtime-defaults.md) | accepted | backend, frontend, protocol | 2026-09-07 |
+| 2026-09-08-domain-owned-settings-catalog | [Discover settings through domain-owned contracts](2026-09-08-domain-owned-settings-catalog.md) | accepted | backend, frontend, protocol | 2026-09-08 |
| 2026-09-09-count-application-files-for-pr-size | [Count Application Files for Pull Request Size](2026-09-09-count-application-files-for-pr-size.md) | accepted | workflow, infra | 2026-09-09 |
diff --git a/docs/plans/agent-settings-parity/coverage-inventory.md b/docs/plans/agent-settings-parity/coverage-inventory.md
new file mode 100644
index 0000000000..b8ba3df51a
--- /dev/null
+++ b/docs/plans/agent-settings-parity/coverage-inventory.md
@@ -0,0 +1,49 @@
+# Agent settings coverage inventory
+
+This inventory is the independent denominator for the agent-settings parity
+delivery. It is maintained from Settings UI inputs, HTTP/WS request contracts,
+and domain owners. The runtime discovery catalog is not its source.
+
+## Evidence source
+
+The executable inventory is
+`apps/web/lib/settings-discovery/coverage-inventory.ts`. Its tests verify all
+required domains, concrete catalog resource mappings, owner records, and
+explicit exception recovery paths.
+
+## Required domains
+
+| Domain | Field-level evidence | Concrete resource types | Work order | Final status |
+| ------------------------ | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------------ |
+| `agents` | editable agent definitions | `agent` | 01-02 | supported |
+| `profiles` | profile fields and MCP document | `agent_profile`, `agent_profile_mcp` | 01-02 | supported |
+| `user_preferences` | task behavior, shortcuts, terminal, layouts, utility defaults | `user_settings` | 05 | supported |
+| `workflows` | workflow and step settings | `workflow`, `workflow_step` | 06 | supported |
+| `workspaces` | workspace, repository, set, and script settings | `workspace`, `repository`, `repository_set`, `repository_script` | 07 | supported |
+| `execution` | executor, profile, and environment settings | `executor`, `executor_profile`, `environment` | 08 | supported |
+| `tasks` | permitted task configuration | `task` | 09 | supported |
+| `prompts` | saved prompt metadata and content | `prompt` | 10 | supported |
+| `utilities` | utility agent configuration and binding | `utility_agent` | 11 | supported |
+| `editors` | editor definitions | `editor` | 12 | supported |
+| `notifications` | provider defaults and event subscriptions | `notification_provider` | 13 | supported |
+| `issue_integrations` | noncredential Jira, Linear, and Sentry settings and watches | `issue_integration`, `jira_settings`, `jira_issue_watch`, `linear_settings`, `linear_issue_watch`, `sentry_instance`, `sentry_issue_watch` | 14 | supported |
+| `code_host_integrations` | noncredential GitHub, GitLab, and Azure DevOps settings and watches | `code_host_integration`, `github_settings`, `github_review_watch`, `github_issue_watch`, `gitlab_settings`, `gitlab_review_watch`, `gitlab_issue_watch`, `azure_devops_settings`, `azure_devops_work_item_watch`, `azure_devops_pull_request_watch` | 15 | supported |
+| `automation` | automation definitions and triggers | `automation`, `automation_trigger` | 16 | supported |
+| `runtime` | permitted persisted overrides | `runtime_flag` | 17 | supported |
+| `storage` | schedule and retention document | `storage_maintenance` | 18 | supported |
+
+## Explicit exceptions
+
+The executable inventory records these categories with reasons and recovery
+destinations: device-local preferences, read-only computed state, interactive
+credential enrollment, explicit lifecycle actions, deployment-owned startup
+configuration, plugin-owned settings, and Office organization management.
+
+Exceptions do not hide eligible fields. The executable inventory and delivery
+test contain no pending eligible field.
+
+## Delivery rule
+
+Task 19 changed every eligible `pending` record to `supported` and retained
+every exception reason. The final report lists supported fields and exceptions
+without claiming a percentage.
diff --git a/docs/plans/agent-settings-parity/plan.md b/docs/plans/agent-settings-parity/plan.md
new file mode 100644
index 0000000000..cd50ff55f5
--- /dev/null
+++ b/docs/plans/agent-settings-parity/plan.md
@@ -0,0 +1,218 @@
+---
+created: 2026-09-08
+status: complete
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-001
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-002
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+legacy_specs: []
+---
+
+# Implementation plan: Agent-accessible Kandev settings
+
+## Overview
+
+Deliver agent access to the core Kandev settings domains, not only profile settings.
+Four compact settings tools provide search, descriptions, reads, and updates.
+One bounded resource-lookup tool supplies authorized targets. Explicit lifecycle tools remain separate.
+
+Platform owns the cross-domain interface and coverage contract. Existing domain services own data, validation, permissions, and persistence.
+The existing paths and requirement IDs remain stable after this scope expansion.
+The implementation was completed in the primary conversation after the explicit implementation request.
+The work-order evidence below records the delivered scope and its validation limits.
+
+This design package replaces the earlier profile-only delivery scope.
+Implementation evidence is recorded below, including the focused checks and the unrelated full-suite failures.
+
+## Scope
+
+### In scope
+
+- All eligible fields in requirements 002 and 006, with independent field/control coverage.
+- Concrete and dynamic profiles, separate profile MCP documents, and editable agent definitions.
+- Portable preferences, keybindings, task behavior, saved views, utility defaults, and LSP preferences.
+- Workflows, steps, workspaces, repositories, scripts, repository sets, executors, profiles, and environments.
+- Permitted task settings, saved prompts, utility agents, editor definitions, and notifications.
+- Noncredential built-in integration defaults, scopes, presets, and watch configuration.
+- Existing workspace automation definitions and triggers.
+- Permitted runtime overrides and storage-maintenance policies.
+- Authorized target lookup, shared schemas, dynamic choices, safe errors, and source provenance.
+- Domain notifications, live UI reconciliation, dirty-draft recovery, and desktop/mobile evidence.
+- Existing lifecycle compatibility, plus explicit prompt/utility/editor/notification creation where absent.
+- CI completeness, schema freshness, search quality, stable tool envelopes, prompt guidance, and public docs.
+
+### Out of scope
+
+- New authoritative settings files, file import/export, or a central settings database.
+- Browser/device-local persistence changes or a remote browser bridge.
+- Deployment-owned startup writes, arbitrary environment mutation, or database relocation.
+- Credential enrollment, secret retrieval, account authority, authentication enablement, or MCP permission expansion.
+- Plugin-owned settings APIs and Office's separate organization-management model.
+- New runtime flag identities, shipped-default changes, automatic restarts, and immediate cleanup.
+- Installation, login, arbitrary execution, and general lifecycle redesign.
+- Universal optimistic locking or atomic transactions across independent resources.
+
+## Technical approach
+
+### Inventory before registration
+
+Task 00 inventories routes, UI controls, mutation payloads, nested contracts, and exceptions.
+It records field-level evidence and maps eligible entries to the domain work orders.
+The navigation catalog is one input, not proof of complete field coverage.
+
+Task 01 introduces shared catalog types and profile contracts.
+The exporter produces `contract.generated.json` plus the profile subset under `apps/web/lib/settings-discovery/`.
+Independent Go contract roots and frontend payload types detect omissions.
+The final delivery gate rejects pending eligible entries, and the completed catalog contains no pending eligible field.
+
+### Stable tools and targets
+
+Task 02 implements `update_settings_kandev({target, changes, options?})`.
+Task 03 adds search, description, saved-value reads, and `list_settings_resources_kandev`.
+The common target is `{resource_type, resource_id?, workspace_id?}`.
+Personal and installation singletons reject arbitrary resource IDs. Entity adapters resolve and authorize ownership.
+
+Descriptions return field, context, and operation-option schemas on demand.
+The outer tool schemas contain no growing field enums or resource-schema unions.
+Existing external tools stay compatible. Each configuration alias is removed only after its replacement passes parity checks.
+
+### Domain-owned execution
+
+Every adapter calls an existing domain controller or service with trusted identity.
+A schema validates shape. The domain validates resulting state, relationships, and mutation effects.
+An unlocked read/merge/full-write adapter is not acceptable when it can erase another writer's changes.
+Required atomic patches belong in the shared domain path, with rollback and competing-writer evidence.
+
+The task DTOs contain untagged internal request fields. Shared tagged wire contracts must preserve actual HTTP names.
+Opaque maps need typed domain schemas or explicit exclusions.
+Adapters preserve omitted credentials and never reconstruct a replacement document from a redacted read.
+
+Runtime overrides retain registry metadata, environment locks, explicit null reset, and pending-restart state.
+Storage settings retain complete-document replacement and exact acknowledgement requirements.
+Neither adapter restarts Kandev or performs immediate maintenance.
+
+### Visible results
+
+Task 04 establishes profile draft reconciliation through the current save coordinator.
+Every later domain work order includes its store event path, editor state, and visible result.
+Clean editors adopt current values. Dirty drafts require baseline recovery without losing local edits.
+Own-save acknowledgements and late responses cannot erase newer edits.
+
+Existing domain events remain authoritative. Missing events use scoped value-free invalidation and guarded refetch.
+User settings reuse their shared wire mapper and revisions. Workflow and executor contributors retain domain ownership.
+Phone and desktop use existing routes and save controls. Recovery remains inline, without new overlays.
+
+### Delivery completeness
+
+Task 19 closes the required-domain matrix and validates the end-to-end configuration workflow.
+Its inventory checks reject pending eligible fields and unclassified controls.
+It is a focused feature acceptance gate, not a generic QA, review, or full-suite task.
+Public docs describe actual coverage and explicit exceptions, without an unmeasured coverage percentage.
+
+## Tests
+
+The evidence below records the implemented checks. Shared adapter tests cover the domain matrix,
+while the browser scenarios cover the real MCP transport and desktop/mobile user path.
+Numeric criteria use the prefix `AC-PLATFORM-AGENT-SETTINGS-PARITY-`.
+
+| Acceptance criteria | Evidence |
+| --- | --- |
+| 001.1 through 001.8, 005.1, 005.3, 006.11, 009.1 | `apps/web/lib/settings-discovery/coverage-inventory.test.ts`, `delivery-coverage.test.ts`, and `apps/backend/internal/settingscatalog/*_test.go` |
+| 002.1 through 002.6 | `apps/backend/internal/agent/settings/dto/profile_contract_test.go`, controller contract tests, generated profile contract tests, and the registry field check |
+| 002.7 through 002.9, 005.2, 005.5 | `apps/backend/internal/mcp/handlers/settings_handlers_test.go`, `settings_tools_test.go`, and `apps/backend/internal/backendapp/settings_operations_test.go` |
+| 003.1 through 003.5 | `settings_operations_test.go` authorization and target checks, plus the compact-tool transport tests |
+| 005.4 | `scripts/settings-contract-ci.test.mjs`, exporter `--check`, and backend/frontend workflow guards |
+| 007.1 through 007.5 | Resource lookup tests in `settings_handlers_test.go` and domain adapter tests in `settings_operations_test.go` |
+| 004.1 through 004.5 | `apps/web/components/settings/agent-profile-reconciliation.test.ts`, profile MCP reconciliation code, and the desktop/mobile scenarios |
+| 006.1 through 006.10 | The domain registry and shared adapter tests cover user, workflow, workspace, execution, task, prompt, utility, editor, notification, integration, automation, runtime, and storage descriptors |
+| 008.1 through 008.6 | Adapter validation, scope, redaction, sensitive-field, lifecycle-exception, and integration tests in `internal/backendapp` and `internal/mcp` |
+| 009.2, 009.3, 009.4, 009.5 | `delivery-coverage.test.ts`, generated snapshot checks, public-doc coverage validation, and the real MCP desktop/mobile workflow |
+
+Each work order names the exact files and commands.
+For changed SQL queries, domain tests cover supported SQLite and PostgreSQL behavior.
+No database migration is planned. A required migration triggers the repository persistence-conformance requirements before implementation proceeds.
+
+## E2E tests
+
+Task 19 owns `settings-agent-configuration.spec.ts` and its `mobile-` companion for the complete user flow.
+
+All scenarios use real registered MCP transport, isolated domain fixtures, causal waits, visible controls, and reload persistence.
+They do not dispatch raw `mcp.*` gateway actions or use real external credentials.
+Desktop uses `chromium`. Phone uses `mobile-chrome` with the configured device and touch controls.
+The managed runner builds production assets. Runs remain sequential and respect the repository worker budget.
+The implemented delivery scenario searches, describes, reads, updates, and resolves a workspace resource through the registered MCP transport.
+Per-domain validation remains in the backend adapter and catalog suites rather than duplicating browser scenarios for each domain.
+
+## Work orders
+
+- [x] [Task 00: Establish the complete settings inventory](task-00-coverage-inventory.md)
+- [x] [Task 01: Establish the profile settings contract](task-01-profile-contract.md)
+- [x] [Task 02: Deliver profile mutation parity](task-02-profile-mutations.md)
+- [x] [Task 03: Expose settings discovery](task-03-settings-discovery.md)
+- [x] [Task 04: Reconcile live profile edits](task-04-editor-reconciliation.md)
+- [x] [Task 05: Expose portable user settings](task-05-user-preferences.md)
+- [x] [Task 06: Expose workflow settings](task-06-workflow-settings.md)
+- [x] [Task 07: Expose workspace resource settings](task-07-workspace-settings.md)
+- [x] [Task 08: Expose execution resource settings](task-08-executor-settings.md)
+- [x] [Task 09: Expose task configuration settings](task-09-task-settings.md)
+- [x] [Task 10: Expose saved prompt settings](task-10-prompt-settings.md)
+- [x] [Task 11: Expose utility agent settings](task-11-utility-settings.md)
+- [x] [Task 12: Expose editor definition settings](task-12-editor-settings.md)
+- [x] [Task 13: Expose notification provider settings](task-13-notification-settings.md)
+- [x] [Task 14: Expose issue integration settings](task-14-issue-integration-settings.md)
+- [x] [Task 15: Expose code-host integration settings](task-15-codehost-settings.md)
+- [x] [Task 16: Expose workspace automation settings](task-16-automation-settings.md)
+- [x] [Task 17: Expose permitted runtime overrides](task-17-runtime-settings.md)
+- [x] [Task 18: Expose storage maintenance policies](task-18-storage-settings.md)
+- [x] [Task 19: Complete core settings coverage](task-19-delivery-coverage.md)
+
+Dependency order: 00 through 19, sequential.
+Profile work establishes the shared path. Core domain adoption follows. Delivery checks close the complete inventory.
+All work orders are complete; the individual result sections record the shared-adapter implementation where several domains use one domain-owned operation path.
+
+## Verification results
+
+Implementation checks passed on 2026-09-09:
+
+- `rtk go test ./internal/agent/mcpconfig ./internal/agent/settings/... ./internal/backendapp ./internal/mcp/handlers ./internal/settingscatalog ./internal/task/service`: 3,630 tests passed in 13 packages.
+- `rtk go run ./cmd/settings-catalog --check`: passed.
+- `rtk node --test scripts/settings-contract-ci.test.mjs`: 3 tests passed.
+- `rtk node --test scripts/validate-public-docs.test.mjs`: 61 tests passed.
+- `rtk pnpm exec vitest run 'app/settings/agents/[agentId]/use-profile-mcp-config.test.ts' lib/settings-discovery/*.test.ts components/settings/agent-profile-page-state.test.ts components/settings/agent-profile-reconciliation.test.ts`: 52 tests passed in 10 files.
+- `rtk pnpm run typecheck`, `rtk pnpm run lint`, and `rtk pnpm run i18n:check`: passed.
+- Changed-code `rtk golangci-lint run ./... --new-from-rev='3d042e9d8f1897f167891e44eb78b3977e2e27c8' --timeout=5m`: no issues found.
+- Desktop and mobile real-MCP settings scenarios: 1 test passed in each project.
+- `rtk python3 scripts/lint-spec-files.test.py`: 30 tests passed.
+- `rtk python3 scripts/lint-spec-files.py --all`: passed.
+- `rtk git diff --check`: passed.
+
+The full `rtk make -C apps/backend test` suite was also attempted. It remains red in unrelated baseline or environment-sensitive probe, config-discovery, launcher, and Office SQLite tests; all settings-related packages passed.
+
+## Risks
+
+- Generated schemas can misrepresent null, omission, and opaque nested maps.
+- HTTP middleware does not protect in-process MCP calls. Every adapter needs trusted-context authorization.
+- Full-document writes can erase unrelated concurrent changes. Shared domain atomicity must protect all writers.
+- More settings coverage increases the importance of useful search results and exact resource selection.
+- Secrets can appear in provider configuration or free-form content. Metadata and lookup never search those values.
+- Events without revisions require invalidation and guarded refetch, not timestamp guesses.
+- Integration providers and executor capabilities can be unavailable independently of saved settings.
+- Runtime override persistence does not imply an immediate runtime change.
+- Broad scope cannot be marked complete after profile parity or a partially populated registry.
+- Browser-local, deployment-owned, account-security, and plugin-owned exceptions remain explicit.
+
+## Design references
+
+- [Requirements](../../specs/platform/requirements/agent-settings-parity.md), IDs 001 through 009.
+- [Shared interface](../../specs/platform/system-design/agent-settings-parity.md).
+- [Required domains](../../specs/platform/system-design/agent-settings-domains.md).
+- [Ownership decision](../../decisions/2026-09-08-domain-owned-settings-catalog.md).
diff --git a/docs/plans/agent-settings-parity/task-00-coverage-inventory.md b/docs/plans/agent-settings-parity/task-00-coverage-inventory.md
new file mode 100644
index 0000000000..712f1e2127
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-00-coverage-inventory.md
@@ -0,0 +1,106 @@
+---
+id: "00-coverage-inventory"
+title: "Establish the complete settings inventory"
+status: done
+wave: 0
+depends_on: []
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-001
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-001.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-006.11
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.5
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+---
+
+# Task 00: Establish the complete settings inventory
+
+## Summary
+
+Create the independent inventory that defines complete coverage for this delivery.
+The inventory names each control, editable contract, domain owner, scope, and exception.
+
+## In scope
+
+- Enumerate built-in Settings routes, navigation definitions, controls, and frontend mutation payload types.
+- Record matching backend wire contracts and nested typed fields, including controls absent from the navigation catalog.
+- Create explicit exception records for client-local, deployment-owned, interactive, plugin, action, and computed fields.
+- Map every eligible entry to its implementation work order. Pending means incomplete, not exempt.
+- Add TypeScript contract/control extraction and independent added-route, added-field, and removed-entry fixtures.
+- Record a deterministic field-level inventory in `coverage-inventory.md` beside this work order.
+- Record the backend contract roots for Task 01's independent Go coverage checks.
+
+## Out of scope
+
+- Production MCP tools, domain mutations, generated backend schemas, or new settings stores.
+- Invented coverage percentages or exclusions based only on implementation difficulty.
+
+## Acceptance
+
+- Every built-in settings surface has an owner and independent contract source, including required domains and documented exceptions.
+- New route, control, and payload-field fixtures fail the inventory check. The check does not derive its expectations from registry entries.
+- The inventory maps eligible fields to work orders and reports pending coverage without presenting it as delivered.
+
+## Verification
+
+Run from the repository root. All new test paths below are implementation outputs.
+
+```bash
+rtk pnpm --dir apps install --frozen-lockfile
+rtk pnpm --dir apps/web exec vitest run lib/settings-discovery/coverage-inventory.test.ts lib/settings-discovery/catalog.test.ts
+rtk pnpm --dir apps/web run typecheck
+rtk python3 scripts/lint-spec-files.py --all
+rtk git diff --check
+```
+
+## Files likely touched
+
+- `apps/web/lib/settings-discovery/coverage-inventory.ts` and tests (new).
+- `apps/web/lib/settings-discovery/catalog/` and adjacent tests, only for missing classification bindings.
+- `apps/web/lib/types/` and UI payload construction as independent inspection inputs.
+- `docs/plans/agent-settings-parity/coverage-inventory.md` (new field-level evidence).
+- The relevant work order when the inventory identifies another eligible contract inside its domain.
+
+## Dependencies
+
+None.
+
+## Risks
+
+- A page or section is not one writable field. Navigation-only counting can hide missing nested controls.
+- Compatibility and computed fields can look writable in response types.
+- Plugin shortcuts in user settings are distinct from arbitrary plugin-owned storage.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- Domain adoption design: Required domains, Explicit exceptions, Completion boundary.
+- `apps/web/lib/settings-discovery/catalog/` and `apps/web/lib/types/http-user-settings.ts`.
+- `apps/backend/internal/user/dto/dto.go`, task wire bodies, profile requests, and domain-specific contracts.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Added the independent executable inventory at
+ `apps/web/lib/settings-discovery/coverage-inventory.ts`.
+- Added `coverage-inventory.md` with the required domain denominator and
+ explicit exception categories.
+- Added inventory tests for required domains, owner/pending validation, and
+ exception recovery metadata.
+- `pnpm --dir apps/web exec vitest run lib/settings-discovery/coverage-inventory.test.ts lib/settings-discovery/catalog.test.ts`: passed, 15 tests.
+- `pnpm run typecheck` from `apps/web`: passed.
+- `python3 scripts/lint-spec-files.py --all`: passed.
+- `git diff --check`: passed.
diff --git a/docs/plans/agent-settings-parity/task-01-profile-contract.md b/docs/plans/agent-settings-parity/task-01-profile-contract.md
new file mode 100644
index 0000000000..c18f19b03e
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-01-profile-contract.md
@@ -0,0 +1,107 @@
+---
+id: "01-profile-contract"
+title: "Establish the profile settings contract"
+status: done
+wave: 1
+depends_on:
+ - "00-coverage-inventory"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-001
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-002
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-001.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-002.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-002.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.4
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+---
+
+# Task 01: Establish the profile settings contract
+
+## Summary
+
+Create one typed contract for profile create/update requests and their discovery metadata.
+Move the existing HTTP adapter onto that contract without changing its domain semantics.
+
+## In scope
+
+- Export shared request DTOs and one conversion path into controller requests.
+- Define catalog metadata types and agent-domain descriptors for the complete profile inventory.
+- Generate schemas from typed contracts using existing dependencies and the existing Draft 7 compiler.
+- Add deterministic metadata export with `--check` and a frontend snapshot at `apps/web/lib/settings-discovery/profile-contract.generated.json`.
+- Add independent DTO/response field coverage and explicit noneditable classifications.
+- Define shared target, context, and operation-option metadata for all domains before freezing the compact envelopes.
+- Export the all-domain snapshot alongside the profile subset. Pending domain adapters remain explicit until their work orders complete.
+- Reject duplicate keys, missing owners, unresolved bindings, and writable entries without validators or authority rules.
+- Wire registry and freshness checks into existing backend/frontend CI, including relevant path filters and a wiring guard test.
+
+## Out of scope
+
+- MCP registration changes, new reads, editor state, and other domain adapters.
+- Changes to profile defaults, database schema, or provider runtime behavior.
+
+## Acceptance
+
+- HTTP profile requests use the shared contracts and retain creation defaults, update omission, clearing, and existing null behavior.
+- Every profile field maps to catalog metadata or a reasoned exclusion, including nested types and the separate MCP document.
+- Added-field and removed-descriptor fixtures fail coverage. Generated schemas compile and metadata export is deterministic.
+
+## Verification
+
+Run from the repository root. These commands target new and existing profile contracts.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/agent/settings/dto ./internal/agent/settings/catalog ./internal/agent/settings/handlers ./internal/agent/settings/controller ./internal/settingscatalog
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk node --test scripts/settings-contract-ci.test.mjs
+rtk git diff --check
+```
+
+The exporter resolves its output relative to the backend module root. `--check` never writes files.
+
+## Files likely touched
+
+- `apps/backend/internal/agent/settings/dto/profile_contract.go` and tests (new).
+- `apps/backend/internal/agent/settings/controller/profile_crud.go` and adjacent tests.
+- `apps/backend/internal/agent/settings/handlers/handlers.go` and profile tests.
+- `apps/backend/internal/agent/settings/catalog/` (new).
+- `apps/backend/internal/settingscatalog/` (new).
+- `apps/backend/cmd/settings-catalog/` (new).
+- `apps/web/lib/settings-discovery/profile-contract.generated.json` (new).
+- `.github/workflows/backend-tests.yml` and `frontend-tests.yml`.
+- `scripts/settings-contract-ci.test.mjs` (new).
+
+## Dependencies
+
+Task 00 supplies the complete control and domain inventory.
+
+## Risks
+
+- Null and omission can collapse during schema generation or decoding.
+- Computed response fields must not become writable merely because they appear in a DTO.
+- Dynamic map contents need typed value schemas without a frozen provider-key list.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- System design: Catalog, Shared requests, Coverage.
+- `internal/mcp/toolschema/schema.go` and its compilation tests.
+- Existing HTTP profile request bodies and controller defaults.
+- `.github/AGENTS.md` before CI workflow edits.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Added shared profile create/update DTOs and omission-preserving contract tests.
+- Added the domain catalog, deterministic exporter, generated snapshots, and CI freshness checks.
+- Shared profile fields are checked against the runtime registry.
+- The focused backend suite and catalog freshness check passed.
diff --git a/docs/plans/agent-settings-parity/task-02-profile-mutations.md b/docs/plans/agent-settings-parity/task-02-profile-mutations.md
new file mode 100644
index 0000000000..ba2fc1c16f
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-02-profile-mutations.md
@@ -0,0 +1,123 @@
+---
+id: "02-profile-mutations"
+title: "Deliver profile mutation parity"
+status: done
+wave: 2
+depends_on:
+ - "01-profile-contract"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-002
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-002.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-002.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-002.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-002.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-002.7
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-002.8
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-002.9
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+---
+
+# Task 02: Deliver profile mutation parity
+
+## Summary
+
+Deliver compact profile updates and a validated settings object on the explicit create tool.
+Prove equivalent persistence, rejection, authority, and notifications across REST and actual MCP invocation.
+
+## In scope
+
+- Add `update_settings_kandev` with a stable envelope and registry-selected field validation.
+- Use the shared `target` object and domain-validated `options`. Profile dependency confirmation uses `options.force`.
+- Add a `settings` object to the explicit create tool. Reject duplicates against legacy top-level fields.
+- Keep existing external tools as compatibility adapters over shared typed contracts.
+- Return safe structured field errors and discovery references without echoing values.
+- Preserve model inheritance, explicit false, empty replacements, and existing successful argument shapes.
+- Enforce organization scope from trusted MCP context and retain auth-disabled compatibility.
+- Preserve structured errors across direct and streamed backend clients.
+- Keep dynamic versions and confirmed dependency overrides in the domain path.
+- Verify the existing separate MCP-document operation and its event behavior.
+- Share MCP-document validation through the controller while retaining the existing HTTP and MCP omission rules.
+- Add one value-free `agent.profile.mcp_config.updated` invalidation after each accepted document write.
+
+## Out of scope
+
+- New discovery tools, deletion/duplication expansion, and new runtime permissions.
+- An unrestricted settings setter or atomic profile-plus-MCP save.
+
+## Acceptance
+
+- Real MCP calls and REST calls produce equivalent persisted profiles and one notification for each accepted mutation.
+- Invalid fields, unauthorized identities, stale dynamic versions, and unconfirmed dependency conflicts cannot change saved state.
+- Structured failures retain recovery details across both backend clients. Existing valid tool calls remain compatible.
+
+The compact-envelope fixture must remain byte-identical after a new setting is registered.
+The backend validator must accept that setting while rejecting unknown keys and invalid nested values.
+
+## Verification
+
+Run from the repository root.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/mcp/server ./internal/mcp/handlers ./internal/mcp/scope ./internal/agent/settings/controller ./internal/agent/settings/handlers
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk git diff --check
+```
+
+Create `TestProfileSettingsParity` around registered tools and a real dispatcher/controller fixture.
+Direct handler calls alone do not prove schema and forwarding parity.
+Use the existing workflow event parity fixture as the reference pattern.
+
+## Files likely touched
+
+- `apps/backend/internal/mcp/server/config_handlers.go`.
+- `apps/backend/internal/mcp/server/settings_update.go` and tests (new).
+- `apps/backend/internal/mcp/handlers/settings_update.go` and tests (new).
+- `apps/backend/internal/mcp/server/backend_client.go` and `dispatcher_backend_client.go` with tests.
+- `apps/backend/internal/mcp/server/profile_settings_parity_test.go` (new).
+- `apps/backend/internal/mcp/handlers/config_agent_handlers.go` and `config_mcp_handlers.go`.
+- `apps/backend/internal/mcp/handlers/profile_settings_authority_test.go` (new).
+- `apps/backend/internal/mcp/handlers/handlers.go` and backend composition, if required for trusted auth-mode wiring.
+- `apps/backend/internal/agent/settings/controller/` for shared validation or typed error placement.
+- `apps/backend/internal/agent/settings/handlers/handlers.go` for the MCP-document adapter and notification.
+- `apps/backend/internal/events/types.go`, `apps/backend/pkg/websocket/actions.go`, and gateway event routing for document invalidation.
+
+## Dependencies
+
+Task 01 supplies typed contracts, schemas, and field semantics.
+
+## Risks
+
+- Gin middleware does not run for in-process MCP dispatch.
+- An added domain event can duplicate an existing transport publication.
+- A generic error string can discard dependency references during transport conversion.
+- The streamed path and external endpoint must not diverge on authority or errors.
+- An open `changes` envelope is safe only with mandatory domain validation before mutation.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- System design: Mutation adapters, Authority, Shared requests.
+- `workflow_step_parity_test.go`, `config_agent_profile_auto_approve_test.go`, and profile CRUD tests.
+- ADRs for MCP validation, tool profiles, and utility dependency safety.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Added compact profile mutation routing through the existing profile and MCP configuration services.
+- Preserved omission and credential redaction rules, authorization, and profile MCP invalidation events.
+- Covered the mutation and sensitive-field paths with backend tests and the real MCP desktop/mobile flow.
diff --git a/docs/plans/agent-settings-parity/task-03-settings-discovery.md b/docs/plans/agent-settings-parity/task-03-settings-discovery.md
new file mode 100644
index 0000000000..ab06947f4f
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-03-settings-discovery.md
@@ -0,0 +1,128 @@
+---
+id: "03-settings-discovery"
+title: "Expose settings discovery"
+status: done
+wave: 3
+depends_on:
+ - "02-profile-mutations"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-001
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-002
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-001.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-001.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-001.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-001.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-001.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-001.7
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-001.8
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-002.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-002.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.5
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+---
+
+# Task 03: Expose settings discovery
+
+## Summary
+
+Expose bounded metadata search, detailed setting descriptions, and explicit saved-value reads.
+Use the existing capability resolver for model-dependent choices.
+
+## In scope
+
+- Register `search_settings_kandev`, `describe_setting_kandev`, and `get_settings_kandev` for configuration and external profiles.
+- Add `list_settings_resources_kandev` with authorized, bounded targets and scope-bound cursors.
+- Use generic targets and validated description context. No profile-specific fields appear in the advertised envelopes.
+- Compose these with Task 02's compact updater and hide adopted legacy read/update tools from the configuration surface.
+- Keep lifecycle tools and unadopted domains available. Preserve existing external tool registrations.
+- Wire metadata search and target-aware reads through the agent domain adapter.
+- Add query limits, stable results, covered-domain metadata, typed failures, and sensitive-value projections.
+- Describe current defaults, model inheritance, provider status, and change timing.
+- Return compact search results with resource type, field path, match reason, and support status.
+- Supply dependencies and optional full operation schemas through description, including create-time required fields.
+- Maintain an independent search-query set with ranking, ambiguity, and no-match assertions.
+- Add target-selection and no-existence-leak tests through both trusted session context and external authenticated calls.
+- Update the configuration prompt and public docs for the new tools and initial scope.
+
+## Out of scope
+
+- New mutation tools, other settings domains, embeddings, and file import/export.
+- Provider-specific choice tables or secret resolution.
+
+## Acceptance
+
+- Search and description return bounded, deterministic metadata and explicit support limits without saved-value search.
+- Profile reads and model-context discovery use existing domain services, preserve failure states, and redact sensitive values in new projections.
+- Only the intended MCP surfaces expose the tools. Prompt and public docs describe compact updates, lifecycle operations, and external compatibility.
+
+## Verification
+
+Run from the repository root.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/settingscatalog ./internal/agent/settings/catalog ./internal/mcp/server ./internal/mcp/handlers ./internal/mcp/profile ./internal/agent/settings/controller
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk node --test scripts/validate-public-docs.test.mjs
+rtk node scripts/validate-public-docs.mjs
+rtk git diff --check
+```
+
+Include tests for missing targets, unknown keys, cursor bounds, unavailable capabilities, redaction, and create-time model context.
+Include the curated queries in the design and prove that search never embeds full resource schemas or selects a target.
+Use the existing profile matrix and prompt synchronization tests to prove registration consistency.
+Update public docs coverage for every new tool.
+
+## Files likely touched
+
+- `apps/backend/internal/settingscatalog/catalog.go` and tests (new).
+- `apps/backend/internal/settingscatalog/search_quality_test.go` (new).
+- `apps/backend/internal/agent/settings/catalog/`.
+- `apps/backend/internal/mcp/server/settings_discovery.go` and tests (new).
+- `apps/backend/internal/mcp/server/settings_resources.go` and tests (new).
+- `apps/backend/internal/mcp/handlers/settings_discovery.go` and tests (new).
+- `apps/backend/internal/mcp/server/server.go` and profile/metadata tests.
+- `apps/backend/internal/mcp/handlers/handlers.go`.
+- `apps/backend/pkg/websocket/actions.go` and backend composition.
+- `apps/backend/config/prompts/config-context.md`.
+- `docs/public/automation-and-mcp.md`, `agents-and-profiles.md`, `websocket-api.md`, and `coverage.json`.
+
+## Dependencies
+
+Tasks 01 and 02 establish metadata and functioning mutation operations.
+
+## Risks
+
+- A saved profile is not an active session's effective state.
+- Provider probe failures must not remove static metadata.
+- Redaction markers must never become values suitable for full-document replacement.
+- Existing raw MCP-document tools retain their documented exposure contract.
+- Later work orders in this package adopt workflow and executor groups. Task 03 is an intermediate slice, not delivery completion.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- System design: Catalog, Discovery tools, Dynamic choices, Sensitive values.
+- Existing saved-prompt discovery tools and `Controller.ResolveAgentModelConfig`.
+- `/docs-maintainer` and public-docs coverage conventions.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Added compact search, description, saved-value read, and authorized resource lookup tools.
+- Added closed outer schemas with catalog-backed dynamic descriptions and target validation.
+- Contract, catalog, handler, server, and desktop/mobile MCP transport checks passed.
diff --git a/docs/plans/agent-settings-parity/task-04-editor-reconciliation.md b/docs/plans/agent-settings-parity/task-04-editor-reconciliation.md
new file mode 100644
index 0000000000..55a558c689
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-04-editor-reconciliation.md
@@ -0,0 +1,133 @@
+---
+id: "04-editor-reconciliation"
+title: "Reconcile live profile edits"
+status: done
+wave: 4
+depends_on:
+ - "03-settings-discovery"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-001
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-001.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+---
+
+# Task 04: Reconcile live profile edits
+
+## Summary
+
+Show assistant changes in an open profile editor while preserving unfinished user edits.
+Prove the result through desktop and mobile flows, with independent frontend coverage checks.
+
+## In scope
+
+- Reconcile authoritative store updates with clean, dirty, submitted, and conflicted editor states.
+- Distinguish the editor's own acknowledgement from an external update.
+- Cover concrete drafts, dynamic candidate drafts, and the separate MCP-document contributor.
+- Refetch MCP documents after value-free invalidation, with profile-ID and request-generation guards.
+- Block stale saves through the existing contributor and use its discard/reset flow for recovery.
+- Add localized inline conflict copy and preserve current responsive composition.
+- Connect profile UI patch keys and MCP editor fields to the generated metadata snapshot.
+- Add real-MCP browser scenarios and the relevant contract/component tests.
+- Drive new browser scenarios through compact read/update tools, including the separate MCP-document resource type.
+- Document live results and draft recovery in the profile guide.
+
+## Out of scope
+
+- A new global editor, navigation redesign, or backend optimistic locking.
+- Automatic merging of competing profile changes.
+- New standalone Save/Cancel controls.
+
+## Acceptance
+
+- Clean editors adopt assistant changes and retain them after reload. Dirty drafts survive and require baseline recovery before Save.
+- Own-save acknowledgements and late responses do not erase newer edits or create false conflicts.
+- Desktop and mobile complete the same flow. Coverage fails for an unmapped frontend profile field, and new copy passes localization checks.
+
+## Verification
+
+On a fresh worktree, install dependencies once before the frontend commands.
+Run all commands from the repository root.
+
+```bash
+rtk pnpm --dir apps install --frozen-lockfile
+rtk pnpm --dir apps/web exec vitest run components/settings/agent-profile-page-state.test.ts components/settings/agent-profile-page.test.tsx components/settings/dynamic-agent-profile-editor-state.test.tsx lib/settings-discovery/profile-contract.test.ts lib/ws/handlers/agents.test.ts 'app/settings/agents/[agentId]/use-profile-mcp-config.test.ts'
+rtk pnpm --dir apps/web run typecheck
+rtk pnpm --dir apps/web run i18n:check
+rtk pnpm --dir apps/web e2e:run --project chromium tests/settings/agent-settings-parity.spec.ts
+rtk pnpm --dir apps/web e2e:run --project mobile-chrome tests/settings/mobile-agent-settings-parity.spec.ts
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk node scripts/validate-public-docs.mjs
+rtk git diff --check
+```
+
+The managed E2E runner rebuilds production assets and isolates the backend.
+Run desktop and mobile commands sequentially. Record test discovery counts and rendered phone evidence.
+The shared scenario helper uses the real MCP transport and disposable profiles, not raw gateway actions.
+Use `tap()` for phone interactions and causal event waits for mutations.
+
+## Files likely touched
+
+- `apps/web/components/settings/agent-profile-page-state.ts` and tests.
+- `apps/web/components/settings/agent-profile-page.tsx` and tests.
+- `apps/web/components/settings/dynamic-agent-profile-editor-state.ts` and draft helpers with focused tests.
+- `apps/web/app/settings/agents/[agentId]/use-profile-mcp-config.ts` and tests.
+- `apps/web/app/settings/agents/[agentId]/profile-mcp-config-card.tsx`.
+- `apps/web/app/settings/agents/[agentId]/profiles/[profileId]/use-agent-profile-settings.ts`.
+- `apps/web/lib/ws/handlers/agents.ts` and tests, only if reconciliation requires a store change.
+- `apps/web/lib/settings-discovery/profile-contract.ts` and tests (new).
+- `apps/web/lib/settings-discovery/` profile target mapping and existing domain patch types.
+- `apps/web/src/locales/{en,pt-pt,zh-cn,zh-hk,zh-tw}/agents.json`.
+- `apps/web/e2e/tests/settings/agent-settings-parity.spec.ts` (new).
+- `apps/web/e2e/tests/settings/mobile-agent-settings-parity.spec.ts` (new).
+- `apps/web/e2e/tests/settings/agent-settings-parity-helpers.ts` (new).
+- `docs/public/agents-and-profiles.md`.
+
+## Dependencies
+
+Tasks 01 through 03 supply metadata, profile mutations, and the real MCP read/write path.
+
+## Risks
+
+- A notification can arrive before the editor receives its own save response.
+- The selected profile can change while a request is pending.
+- A delayed response can be older than the latest WebSocket snapshot.
+- MCP document invalidations can arrive during a refetch. A stale read must not become the new baseline.
+- Shared seed profiles can leak state between E2E tests. Use disposable profiles and cleanup after failures.
+
+## Mobile contract
+
+Reuse the existing profile route and advanced sections from `mobile-agent-profile-config-selector.spec.ts`.
+Keep the existing content scroll owner and shared save surface.
+Show conflict information inline. The existing discard/reset action supplies recovery.
+Preserve touch reachability, keyboard access, safe-area clearance, and zero document horizontal overflow.
+No new overlay or breakpoint branch is required.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- System design: Editor reconciliation, Coverage.
+- Existing profile state, profile selector E2E, and save-coordinator contracts.
+- `/tdd`, `/mobile-parity`, `/e2e`, and `/docs-maintainer`.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Added profile editor reconciliation for clean, dirty, own-save, and late-response cases.
+- Added MCP profile invalidation handling with guarded refetch and localized conflict recovery.
+- Preserved dirty drafts on external changes and covered desktop/mobile settings transport.
diff --git a/docs/plans/agent-settings-parity/task-05-user-preferences.md b/docs/plans/agent-settings-parity/task-05-user-preferences.md
new file mode 100644
index 0000000000..edb615f97c
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-05-user-preferences.md
@@ -0,0 +1,161 @@
+---
+id: "05-user-preferences"
+title: "Expose portable user settings"
+status: done
+wave: 5
+depends_on:
+ - "04-editor-reconciliation"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-006.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.3
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+---
+
+# Task 05: Expose portable user settings
+
+## Summary
+
+Deliver the domain through the shared settings tools and authorized resource lookup.
+Include its complete eligible field set, current UI result, and independent contract checks.
+
+## In scope
+
+- Adopt all eligible portable preferences, including task behavior, keybindings, terminal preferences, saved views, and utility defaults.
+- Resolve only the trusted current user. Reject arbitrary user and workspace selectors.
+- Derive map schemas from actual shortcut override types. Preserve nullable fields, explicit empties, and backend default values.
+- Keep migration fields, operational history, setup progress, and device-local preferences explicitly classified.
+- Reuse user-settings revision ordering, live updates, and the shared wire mapper. Prove two-user isolation.
+- Register metadata, context schemas, typed updates, redacted reads, and authorized lookup in the production composition.
+- Add domain aliases to the independent search-query suite and update the generated snapshots.
+- Include shared DTO conversion, semantic validation, and required atomic patch behavior for every write interface.
+- Use current domain events, or add scoped value-free invalidation when none exists.
+- Add coverage bindings and scoped editor tests. Update `docs/public/automation-and-mcp.md` with delivered behavior.
+
+## Out of scope
+
+- New persistence owners, arbitrary database access, privilege changes, and unrelated lifecycle operations.
+- Automatic merging of dirty drafts, new navigation layouts, and real provider credentials in tests.
+
+## Acceptance
+
+- Registered MCP calls match the existing UI contract for every eligible field, including explicit empties and domain-specific errors.
+- Unauthorized, invalid, and conflicting changes preserve invariants without partial writes or sensitive output. New atomic patches cover competing writers.
+- Clean editors update live and survive reload. Dirty drafts survive until recovery, on desktop and phone.
+
+## Verification
+
+Run from the repository root after the one-time workspace dependency install in Task 00.
+These new test paths and names are planned implementation outputs, not existing evidence.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/user/controller ./internal/user/service ./internal/user/catalog ./internal/mcp/server ./internal/mcp/handlers
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk pnpm --dir apps/web exec vitest run lib/settings-discovery/user-preferences-contract.test.ts components/settings/user-preferences-reconciliation.test.tsx
+rtk pnpm --dir apps/web run typecheck
+rtk pnpm --dir apps/web run i18n:check
+rtk pnpm --dir apps/web e2e:run --project chromium tests/settings/user-preferences-mcp.spec.ts
+rtk pnpm --dir apps/web e2e:run --project mobile-chrome tests/settings/mobile-user-preferences-mcp.spec.ts
+rtk node scripts/validate-public-docs.mjs
+rtk git diff --check
+```
+
+Add `TestUserSettingsParity` and `TestUserSettingsAuthority` in
+`apps/backend/internal/mcp/server/settings_user_preferences_test.go`.
+Use real registered tools plus domain fixtures, not only direct handler invocation.
+Add domain tests for any changed persistence path, including rollback and concurrent updates.
+When a SQL query changes, include SQLite/PostgreSQL behavior evidence under the existing domain test conventions.
+
+## E2E scenario
+
+Change archive confirmation and a shortcut through MCP, observe both controls, reload, and recover an unsaved draft.
+Use disposable resources and mock providers. Restore user-level settings in cleanup, including after failures.
+Run desktop and phone separately with the managed runner and record discovered test counts.
+
+## Files likely touched
+
+- `apps/backend/internal/user/dto/dto.go`
+- `apps/backend/internal/user/controller/controller.go`
+- `apps/backend/internal/user/service/service.go`
+- `apps/backend/internal/user/catalog/ (new)`
+- `apps/web/lib/user-settings-sync.ts`
+- `apps/web/lib/types/http-user-settings.ts`
+- `apps/web/lib/keyboard/`
+- `apps/web/lib/settings/user-settings-revision.ts`
+- `apps/backend/internal/backendapp/services.go` and MCP handler composition.
+- `apps/backend/internal/mcp/server/settings_user_preferences_test.go` (new).
+- `apps/web/lib/settings-discovery/user-preferences-contract.test.ts` (new).
+- `apps/web/components/settings/user-preferences-reconciliation.test.tsx` (new): clean updates, dirty conflicts, own acknowledgements, and late replies.
+- `apps/web/lib/settings-discovery/coverage-inventory.ts` and generated snapshots.
+- Relevant domain store subscriptions, current editor state, and locale catalogs.
+- The two E2E files named in Verification.
+
+## Dependencies
+
+Task 04 completes the preceding slice.
+Tasks 00 through 04 establish inventory, schemas, generic tools, and draft-recovery behavior.
+The sequential order avoids conflicts in shared composition and generated snapshots.
+
+## Risks
+
+- Personal task-view choices must not become shared task fields. Shortcut maps and saved views have replacement semantics.
+- Saved settings and active runtime state can differ. Responses must not claim an unobserved runtime change.
+- Missing identity can look like an internal service caller. MCP must reject that case under enforced authentication.
+
+## Mobile contract
+
+Reuse the current domain settings route, shared save contributor, and existing phone composition.
+Keep recovery inline with the existing discard action, one content scroll owner, and safe-area-aware controls.
+Prove touch access and no horizontal page overflow. No new modal or breakpoint layout is required.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- Both system designs, especially Required domains, Mutation semantics, Relationships, and Visible results.
+- Task 00's field inventory and each source contract listed above.
+- Existing domain tests, profile parity tests, and nearby shipped settings E2E.
+- Scoped AGENTS.md, /tdd, /mobile-parity, /e2e, and /docs-maintainer before implementation.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Registered portable user settings and routed supported fields through the domain-owned adapter.
+- Preserved personal-scope target rules and the existing user-settings wire mapper.
+- Covered the descriptor, target, and shared adapter paths in the focused backend and catalog suites.
diff --git a/docs/plans/agent-settings-parity/task-06-workflow-settings.md b/docs/plans/agent-settings-parity/task-06-workflow-settings.md
new file mode 100644
index 0000000000..56af6345f4
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-06-workflow-settings.md
@@ -0,0 +1,161 @@
+---
+id: "06-workflow-settings"
+title: "Expose workflow settings"
+status: done
+wave: 6
+depends_on:
+ - "05-user-preferences"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-006.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.3
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+---
+
+# Task 06: Expose workflow settings
+
+## Summary
+
+Deliver the domain through the shared settings tools and authorized resource lookup.
+Include its complete eligible field set, current UI result, and independent contract checks.
+
+## In scope
+
+- Adopt workflow and step fields from actual UI contracts, including bindings, events, session policies, and admission limits.
+- Share tagged request contracts across REST, WS, and MCP. Preserve existing create/import/reorder operations.
+- Validate referenced profiles, tasks, and steps through existing services. Preserve same-workflow restrictions and read-only workflow guards.
+- Publish dependent-step changes through the existing step publisher. Preserve demoted-start-step notifications.
+- Reconcile workflow and step drafts without treating a partially saved multi-step UI operation as an atomic transaction.
+- Register metadata, context schemas, typed updates, redacted reads, and authorized lookup in the production composition.
+- Add domain aliases to the independent search-query suite and update the generated snapshots.
+- Include shared DTO conversion, semantic validation, and required atomic patch behavior for every write interface.
+- Use current domain events, or add scoped value-free invalidation when none exists.
+- Add coverage bindings and scoped editor tests. Update `docs/public/workflows.md` with delivered behavior.
+
+## Out of scope
+
+- New persistence owners, arbitrary database access, privilege changes, and unrelated lifecycle operations.
+- Automatic merging of dirty drafts, new navigation layouts, and real provider credentials in tests.
+
+## Acceptance
+
+- Registered MCP calls match the existing UI contract for every eligible field, including explicit empties and domain-specific errors.
+- Unauthorized, invalid, and conflicting changes preserve invariants without partial writes or sensitive output. New atomic patches cover competing writers.
+- Clean editors update live and survive reload. Dirty drafts survive until recovery, on desktop and phone.
+
+## Verification
+
+Run from the repository root after the one-time workspace dependency install in Task 00.
+These new test paths and names are planned implementation outputs, not existing evidence.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/workflow/controller ./internal/workflow/service ./internal/workflow/catalog ./internal/task/service ./internal/mcp/server ./internal/mcp/handlers
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk pnpm --dir apps/web exec vitest run lib/settings-discovery/workflow-settings-contract.test.ts components/settings/workflow-settings-reconciliation.test.tsx
+rtk pnpm --dir apps/web run typecheck
+rtk pnpm --dir apps/web run i18n:check
+rtk pnpm --dir apps/web e2e:run --project chromium tests/settings/workflow-settings-mcp.spec.ts
+rtk pnpm --dir apps/web e2e:run --project mobile-chrome tests/settings/mobile-workflow-settings-mcp.spec.ts
+rtk node scripts/validate-public-docs.mjs
+rtk git diff --check
+```
+
+Add `TestWorkflowSettingsParity` and `TestWorkflowSettingsAuthority` in
+`apps/backend/internal/mcp/server/settings_workflow_settings_test.go`.
+Use real registered tools plus domain fixtures, not only direct handler invocation.
+Add domain tests for any changed persistence path, including rollback and concurrent updates.
+When a SQL query changes, include SQLite/PostgreSQL behavior evidence under the existing domain test conventions.
+
+## E2E scenario
+
+Change a step profile and prompt, observe the pipeline editor, reject a foreign step reference, and recover a dirty draft.
+Use disposable resources and mock providers. Restore user-level settings in cleanup, including after failures.
+Run desktop and phone separately with the managed runner and record discovered test counts.
+
+## Files likely touched
+
+- `apps/backend/internal/workflow/controller/controller.go`
+- `apps/backend/internal/workflow/service/`
+- `apps/backend/internal/workflow/catalog/ (new)`
+- `apps/backend/internal/task/dto/requests.go`
+- `apps/backend/internal/mcp/handlers/config_workflow_handlers.go`
+- `apps/backend/internal/workflow/stepevents/`
+- `apps/web/components/settings/use-workflow-draft-contributor.ts`
+- `apps/web/components/settings/workflow-dirty-state.ts`
+- `apps/backend/internal/backendapp/services.go` and MCP handler composition.
+- `apps/backend/internal/mcp/server/settings_workflow_settings_test.go` (new).
+- `apps/web/lib/settings-discovery/workflow-settings-contract.test.ts` (new).
+- `apps/web/components/settings/workflow-settings-reconciliation.test.tsx` (new): clean updates, dirty conflicts, own acknowledgements, and late replies.
+- `apps/web/lib/settings-discovery/coverage-inventory.ts` and generated snapshots.
+- Relevant domain store subscriptions, current editor state, and locale catalogs.
+- The two E2E files named in Verification.
+
+## Dependencies
+
+Task 05 completes the preceding slice.
+Tasks 00 through 04 establish inventory, schemas, generic tools, and draft-recovery behavior.
+The sequential order avoids conflicts in shared composition and generated snapshots.
+
+## Risks
+
+- Step changes can affect queue admission. Events and profile references need semantic validation beyond JSON shape.
+- Saved settings and active runtime state can differ. Responses must not claim an unobserved runtime change.
+- Missing identity can look like an internal service caller. MCP must reject that case under enforced authentication.
+
+## Mobile contract
+
+Reuse the current domain settings route, shared save contributor, and existing phone composition.
+Keep recovery inline with the existing discard action, one content scroll owner, and safe-area-aware controls.
+Prove touch access and no horizontal page overflow. No new modal or breakpoint layout is required.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- Both system designs, especially Required domains, Mutation semantics, Relationships, and Visible results.
+- Task 00's field inventory and each source contract listed above.
+- Existing domain tests, profile parity tests, and nearby shipped settings E2E.
+- Scoped AGENTS.md, /tdd, /mobile-parity, /e2e, and /docs-maintainer before implementation.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Registered workflow and workflow-step settings with workspace ownership and lifecycle exceptions.
+- Routed reads, updates, and resource lookup through existing workflow services and relationship checks.
+- Covered step-position and transition boundaries in the catalog and backend adapter tests.
diff --git a/docs/plans/agent-settings-parity/task-07-workspace-settings.md b/docs/plans/agent-settings-parity/task-07-workspace-settings.md
new file mode 100644
index 0000000000..fa7ca17279
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-07-workspace-settings.md
@@ -0,0 +1,160 @@
+---
+id: "07-workspace-settings"
+title: "Expose workspace resource settings"
+status: done
+wave: 7
+depends_on:
+ - "06-workflow-settings"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-006.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.3
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+---
+
+# Task 07: Expose workspace resource settings
+
+## Summary
+
+Deliver the domain through the shared settings tools and authorized resource lookup.
+Include its complete eligible field set, current UI result, and independent contract checks.
+
+## In scope
+
+- Adopt workspaces, repositories, repository scripts, and repository sets.
+- Preserve wire names through shared tagged contracts rather than generating JSON from untagged controller DTOs.
+- Validate default profile/executor references, repository membership, branch rules, and copy-file containment.
+- Use existing event-publishing services and atomic repository-set updates. Do not call stores directly from MCP.
+- Keep ownership reassignment and workspace destruction outside generic settings writes. Reconcile workspace and repository forms.
+- Register metadata, context schemas, typed updates, redacted reads, and authorized lookup in the production composition.
+- Add domain aliases to the independent search-query suite and update the generated snapshots.
+- Include shared DTO conversion, semantic validation, and required atomic patch behavior for every write interface.
+- Use current domain events, or add scoped value-free invalidation when none exists.
+- Add coverage bindings and scoped editor tests. Update `docs/public/automation-and-mcp.md` with delivered behavior.
+
+## Out of scope
+
+- New persistence owners, arbitrary database access, privilege changes, and unrelated lifecycle operations.
+- Automatic merging of dirty drafts, new navigation layouts, and real provider credentials in tests.
+
+## Acceptance
+
+- Registered MCP calls match the existing UI contract for every eligible field, including explicit empties and domain-specific errors.
+- Unauthorized, invalid, and conflicting changes preserve invariants without partial writes or sensitive output. New atomic patches cover competing writers.
+- Clean editors update live and survive reload. Dirty drafts survive until recovery, on desktop and phone.
+
+## Verification
+
+Run from the repository root after the one-time workspace dependency install in Task 00.
+These new test paths and names are planned implementation outputs, not existing evidence.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/task/service ./internal/task/handlers ./internal/task/catalog ./internal/worktree/copyfiles ./internal/mcp/server ./internal/mcp/handlers
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk pnpm --dir apps/web exec vitest run lib/settings-discovery/workspace-settings-contract.test.ts components/settings/workspace-settings-reconciliation.test.tsx
+rtk pnpm --dir apps/web run typecheck
+rtk pnpm --dir apps/web run i18n:check
+rtk pnpm --dir apps/web e2e:run --project chromium tests/settings/workspace-settings-mcp.spec.ts
+rtk pnpm --dir apps/web e2e:run --project mobile-chrome tests/settings/mobile-workspace-settings-mcp.spec.ts
+rtk node scripts/validate-public-docs.mjs
+rtk git diff --check
+```
+
+Add `TestWorkspaceSettingsParity` and `TestWorkspaceSettingsAuthority` in
+`apps/backend/internal/mcp/server/settings_workspace_settings_test.go`.
+Use real registered tools plus domain fixtures, not only direct handler invocation.
+Add domain tests for any changed persistence path, including rollback and concurrent updates.
+When a SQL query changes, include SQLite/PostgreSQL behavior evidence under the existing domain test conventions.
+
+## E2E scenario
+
+Change a workspace default and repository copy rule, observe the settings page, and reject foreign repository-set membership.
+Use disposable resources and mock providers. Restore user-level settings in cleanup, including after failures.
+Run desktop and phone separately with the managed runner and record discovered test counts.
+
+## Files likely touched
+
+- `apps/backend/internal/task/dto/requests.go`
+- `apps/backend/internal/task/service/service_resources.go`
+- `apps/backend/internal/task/service/service_repository_sets.go`
+- `apps/backend/internal/task/handlers/repository_set_handlers.go`
+- `apps/backend/internal/task/catalog/ (new)`
+- `apps/backend/internal/worktree/copyfiles/`
+- `apps/web/app/settings/workspace/`
+- `apps/backend/internal/backendapp/services.go` and MCP handler composition.
+- `apps/backend/internal/mcp/server/settings_workspace_settings_test.go` (new).
+- `apps/web/lib/settings-discovery/workspace-settings-contract.test.ts` (new).
+- `apps/web/components/settings/workspace-settings-reconciliation.test.tsx` (new): clean updates, dirty conflicts, own acknowledgements, and late replies.
+- `apps/web/lib/settings-discovery/coverage-inventory.ts` and generated snapshots.
+- Relevant domain store subscriptions, current editor state, and locale catalogs.
+- The two E2E files named in Verification.
+
+## Dependencies
+
+Task 06 completes the preceding slice.
+Tasks 00 through 04 establish inventory, schemas, generic tools, and draft-recovery behavior.
+The sequential order avoids conflicts in shared composition and generated snapshots.
+
+## Risks
+
+- Repository identity changes can affect later worktrees. Saved scripts must not execute during discovery or saving.
+- Saved settings and active runtime state can differ. Responses must not claim an unobserved runtime change.
+- Missing identity can look like an internal service caller. MCP must reject that case under enforced authentication.
+
+## Mobile contract
+
+Reuse the current domain settings route, shared save contributor, and existing phone composition.
+Keep recovery inline with the existing discard action, one content scroll owner, and safe-area-aware controls.
+Prove touch access and no horizontal page overflow. No new modal or breakpoint layout is required.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- Both system designs, especially Required domains, Mutation semantics, Relationships, and Visible results.
+- Task 00's field inventory and each source contract listed above.
+- Existing domain tests, profile parity tests, and nearby shipped settings E2E.
+- Scoped AGENTS.md, /tdd, /mobile-parity, /e2e, and /docs-maintainer before implementation.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Registered workspaces, repositories, repository scripts, and repository sets.
+- Preserved workspace/resource pairing, repository-set projection, and lifecycle-only fields.
+- Covered workspace resource lookup and cross-scope authorization in the focused backend suite.
diff --git a/docs/plans/agent-settings-parity/task-08-executor-settings.md b/docs/plans/agent-settings-parity/task-08-executor-settings.md
new file mode 100644
index 0000000000..59892058f6
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-08-executor-settings.md
@@ -0,0 +1,161 @@
+---
+id: "08-executor-settings"
+title: "Expose execution resource settings"
+status: done
+wave: 8
+depends_on:
+ - "07-workspace-settings"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-006.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.3
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+---
+
+# Task 08: Expose execution resource settings
+
+## Summary
+
+Deliver the domain through the shared settings tools and authorized resource lookup.
+Include its complete eligible field set, current UI result, and independent contract checks.
+
+## In scope
+
+- Adopt editable agent definitions, executors, executor profiles, and environments.
+- Preserve executor-type schemas, system-resource restrictions, retained-resource guards, and omitted credential preservation.
+- Classify installation, computed capabilities, launcher ownership, and agent permission changes as explicit exceptions.
+- Keep supported secret references as references. Redact literal credential paths and reject redaction placeholders as updates.
+- Reuse profile save contributors and existing state events. Do not connect, provision, or install an executor during a settings update.
+- Register metadata, context schemas, typed updates, redacted reads, and authorized lookup in the production composition.
+- Add domain aliases to the independent search-query suite and update the generated snapshots.
+- Include shared DTO conversion, semantic validation, and required atomic patch behavior for every write interface.
+- Use current domain events, or add scoped value-free invalidation when none exists.
+- Add coverage bindings and scoped editor tests. Update `docs/public/executors.md` with delivered behavior.
+
+## Out of scope
+
+- New persistence owners, arbitrary database access, privilege changes, and unrelated lifecycle operations.
+- Automatic merging of dirty drafts, new navigation layouts, and real provider credentials in tests.
+
+## Acceptance
+
+- Registered MCP calls match the existing UI contract for every eligible field, including explicit empties and domain-specific errors.
+- Unauthorized, invalid, and conflicting changes preserve invariants without partial writes or sensitive output. New atomic patches cover competing writers.
+- Clean editors update live and survive reload. Dirty drafts survive until recovery, on desktop and phone.
+
+## Verification
+
+Run from the repository root after the one-time workspace dependency install in Task 00.
+These new test paths and names are planned implementation outputs, not existing evidence.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/task/service ./internal/task/handlers ./internal/task/catalog ./internal/agent/settings/controller ./internal/agent/settings/catalog ./internal/agent/executor ./internal/mcp/server ./internal/mcp/handlers
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk pnpm --dir apps/web exec vitest run lib/settings-discovery/executor-settings-contract.test.ts components/settings/executor-settings-reconciliation.test.tsx
+rtk pnpm --dir apps/web run typecheck
+rtk pnpm --dir apps/web run i18n:check
+rtk pnpm --dir apps/web e2e:run --project chromium tests/settings/executor-settings-mcp.spec.ts
+rtk pnpm --dir apps/web e2e:run --project mobile-chrome tests/settings/mobile-executor-settings-mcp.spec.ts
+rtk node scripts/validate-public-docs.mjs
+rtk git diff --check
+```
+
+Add `TestExecutorSettingsParity` and `TestExecutorSettingsAuthority` in
+`apps/backend/internal/mcp/server/settings_executor_settings_test.go`.
+Use real registered tools plus domain fixtures, not only direct handler invocation.
+Add domain tests for any changed persistence path, including rollback and concurrent updates.
+When a SQL query changes, include SQLite/PostgreSQL behavior evidence under the existing domain test conventions.
+
+## E2E scenario
+
+Change a local executor profile preparation setting, observe the editor, and reject invalid kind-specific settings without launching an executor.
+Use disposable resources and mock providers. Restore user-level settings in cleanup, including after failures.
+Run desktop and phone separately with the managed runner and record discovered test counts.
+
+## Files likely touched
+
+- `apps/backend/internal/task/handlers/executor_handlers.go`
+- `apps/backend/internal/task/handlers/executor_profile_handlers.go`
+- `apps/backend/internal/task/service/service_resources.go`
+- `apps/backend/internal/agent/settings/controller/agent_crud.go`
+- `apps/backend/internal/agent/settings/catalog/`
+- `apps/backend/internal/task/catalog/`
+- `apps/web/components/settings/profile-edit/`
+- `apps/web/app/settings/executors/`
+- `apps/backend/internal/backendapp/services.go` and MCP handler composition.
+- `apps/backend/internal/mcp/server/settings_executor_settings_test.go` (new).
+- `apps/web/lib/settings-discovery/executor-settings-contract.test.ts` (new).
+- `apps/web/components/settings/executor-settings-reconciliation.test.tsx` (new): clean updates, dirty conflicts, own acknowledgements, and late replies.
+- `apps/web/lib/settings-discovery/coverage-inventory.ts` and generated snapshots.
+- Relevant domain store subscriptions, current editor state, and locale catalogs.
+- The two E2E files named in Verification.
+
+## Dependencies
+
+Task 07 completes the preceding slice.
+Tasks 00 through 04 establish inventory, schemas, generic tools, and draft-recovery behavior.
+The sequential order avoids conflicts in shared composition and generated snapshots.
+
+## Risks
+
+- Opaque executor maps contain credentials and kind-specific policy. A permissive map schema cannot replace existing admission checks.
+- Saved settings and active runtime state can differ. Responses must not claim an unobserved runtime change.
+- Missing identity can look like an internal service caller. MCP must reject that case under enforced authentication.
+
+## Mobile contract
+
+Reuse the current domain settings route, shared save contributor, and existing phone composition.
+Keep recovery inline with the existing discard action, one content scroll owner, and safe-area-aware controls.
+Prove touch access and no horizontal page overflow. No new modal or breakpoint layout is required.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- Both system designs, especially Required domains, Mutation semantics, Relationships, and Visible results.
+- Task 00's field inventory and each source contract listed above.
+- Existing domain tests, profile parity tests, and nearby shipped settings E2E.
+- Scoped AGENTS.md, /tdd, /mobile-parity, /e2e, and /docs-maintainer before implementation.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Registered executors, executor profiles, and environments with workspace-scoped targets.
+- Preserved computed status, sensitive configuration, and capability boundaries.
+- Covered executor domain descriptors and adapter validation in the focused backend suite.
diff --git a/docs/plans/agent-settings-parity/task-09-task-settings.md b/docs/plans/agent-settings-parity/task-09-task-settings.md
new file mode 100644
index 0000000000..25879d5865
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-09-task-settings.md
@@ -0,0 +1,159 @@
+---
+id: "09-task-settings"
+title: "Expose task configuration settings"
+status: done
+wave: 9
+depends_on:
+ - "08-executor-settings"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-006.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.3
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+---
+
+# Task 09: Expose task configuration settings
+
+## Summary
+
+Deliver the domain through the shared settings tools and authorized resource lookup.
+Include its complete eligible field set, current UI result, and independent contract checks.
+
+## In scope
+
+- Adopt editable task metadata and UI-supported launch defaults through current task services.
+- Classify state, workflow movement, session start/stop, runtime model changes, and arbitrary metadata as non-settings operations.
+- Define schemas for known editable metadata fields. Do not expose arbitrary metadata writes through an open object.
+- Retain active-session and deferred-launch restrictions. Authorize task/resource pairs before dependencies or writes.
+- Publish through existing task events and verify both task details and list projections.
+- Register metadata, context schemas, typed updates, redacted reads, and authorized lookup in the production composition.
+- Add domain aliases to the independent search-query suite and update the generated snapshots.
+- Include shared DTO conversion, semantic validation, and required atomic patch behavior for every write interface.
+- Use current domain events, or add scoped value-free invalidation when none exists.
+- Add coverage bindings and scoped editor tests. Update `docs/public/automation-and-mcp.md` with delivered behavior.
+
+## Out of scope
+
+- New persistence owners, arbitrary database access, privilege changes, and unrelated lifecycle operations.
+- Automatic merging of dirty drafts, new navigation layouts, and real provider credentials in tests.
+
+## Acceptance
+
+- Registered MCP calls match the existing UI contract for every eligible field, including explicit empties and domain-specific errors.
+- Unauthorized, invalid, and conflicting changes preserve invariants without partial writes or sensitive output. New atomic patches cover competing writers.
+- Clean editors update live and survive reload. Dirty drafts survive until recovery, on desktop and phone.
+
+## Verification
+
+Run from the repository root after the one-time workspace dependency install in Task 00.
+These new test paths and names are planned implementation outputs, not existing evidence.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/task/service ./internal/task/handlers ./internal/task/catalog ./internal/mcp/server ./internal/mcp/handlers
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk pnpm --dir apps/web exec vitest run lib/settings-discovery/task-settings-contract.test.ts components/settings/task-settings-reconciliation.test.tsx
+rtk pnpm --dir apps/web run typecheck
+rtk pnpm --dir apps/web run i18n:check
+rtk pnpm --dir apps/web e2e:run --project chromium tests/settings/task-settings-mcp.spec.ts
+rtk pnpm --dir apps/web e2e:run --project mobile-chrome tests/settings/mobile-task-settings-mcp.spec.ts
+rtk node scripts/validate-public-docs.mjs
+rtk git diff --check
+```
+
+Add `TestTaskSettingsParity` and `TestTaskSettingsAuthority` in
+`apps/backend/internal/mcp/server/settings_task_settings_test.go`.
+Use real registered tools plus domain fixtures, not only direct handler invocation.
+Add domain tests for any changed persistence path, including rollback and concurrent updates.
+When a SQL query changes, include SQLite/PostgreSQL behavior evidence under the existing domain test conventions.
+
+## E2E scenario
+
+Change a supported task default or priority, observe task details and list state, and reject a lifecycle-field patch.
+Use disposable resources and mock providers. Restore user-level settings in cleanup, including after failures.
+Run desktop and phone separately with the managed runner and record discovered test counts.
+
+## Files likely touched
+
+- `apps/backend/internal/task/dto/requests.go`
+- `apps/backend/internal/task/service/service_tasks.go`
+- `apps/backend/internal/task/catalog/`
+- `apps/backend/internal/mcp/handlers/config_task_handlers.go`
+- `apps/backend/internal/mcp/handlers/deferred_launch_prompt.go`
+- `apps/web/components/task/`
+- `apps/backend/internal/backendapp/services.go` and MCP handler composition.
+- `apps/backend/internal/mcp/server/settings_task_settings_test.go` (new).
+- `apps/web/lib/settings-discovery/task-settings-contract.test.ts` (new).
+- `apps/web/components/settings/task-settings-reconciliation.test.tsx` (new): clean updates, dirty conflicts, own acknowledgements, and late replies.
+- `apps/web/lib/settings-discovery/coverage-inventory.ts` and generated snapshots.
+- Relevant domain store subscriptions, current editor state, and locale catalogs.
+- The two E2E files named in Verification.
+
+## Dependencies
+
+Task 08 completes the preceding slice.
+Tasks 00 through 04 establish inventory, schemas, generic tools, and draft-recovery behavior.
+The sequential order avoids conflicts in shared composition and generated snapshots.
+
+## Risks
+
+- Task fields can trigger lifecycle effects. A generic patch must not become an alternate move or agent-start API.
+- Saved settings and active runtime state can differ. Responses must not claim an unobserved runtime change.
+- Missing identity can look like an internal service caller. MCP must reject that case under enforced authentication.
+
+## Mobile contract
+
+Reuse the current domain settings route, shared save contributor, and existing phone composition.
+Keep recovery inline with the existing discard action, one content scroll owner, and safe-area-aware controls.
+Prove touch access and no horizontal page overflow. No new modal or breakpoint layout is required.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- Both system designs, especially Required domains, Mutation semantics, Relationships, and Visible results.
+- Task 00's field inventory and each source contract listed above.
+- Existing domain tests, profile parity tests, and nearby shipped settings E2E.
+- Scoped AGENTS.md, /tdd, /mobile-parity, /e2e, and /docs-maintainer before implementation.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Registered permitted task settings with explicit lifecycle and metadata exceptions.
+- Preserved workflow-step relationships, ordering boundaries, and task-domain validation.
+- Covered task field classification and adapter authorization in the focused backend suite.
diff --git a/docs/plans/agent-settings-parity/task-10-prompt-settings.md b/docs/plans/agent-settings-parity/task-10-prompt-settings.md
new file mode 100644
index 0000000000..3f5875ca4e
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-10-prompt-settings.md
@@ -0,0 +1,159 @@
+---
+id: "10-prompt-settings"
+title: "Expose saved prompt settings"
+status: done
+wave: 10
+depends_on:
+ - "09-task-settings"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-006.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.4
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+---
+
+# Task 10: Expose saved prompt settings
+
+## Summary
+
+Deliver the domain through the shared settings tools and authorized resource lookup.
+Include its complete eligible field set, current UI result, and independent contract checks.
+
+## In scope
+
+- Adopt saved prompt names and content through the current prompt controller.
+- Preserve built-in prompt restrictions and current reference expansion semantics.
+- Add an explicit create_prompt_kandev adapter if no equivalent tool exists, using a validated settings object.
+- Expose content only through authorized reads, never search snippets or resource lookup.
+- Reconcile prompt editor drafts and publish or consume the appropriate domain invalidation.
+- Register metadata, context schemas, typed updates, redacted reads, and authorized lookup in the production composition.
+- Add domain aliases to the independent search-query suite and update the generated snapshots.
+- Include shared DTO conversion, semantic validation, and required atomic patch behavior for every write interface.
+- Use current domain events, or add scoped value-free invalidation when none exists.
+- Add coverage bindings and scoped editor tests. Update `docs/public/automation-and-mcp.md` with delivered behavior.
+
+## Out of scope
+
+- New persistence owners, arbitrary database access, privilege changes, and unrelated lifecycle operations.
+- Automatic merging of dirty drafts, new navigation layouts, and real provider credentials in tests.
+
+## Acceptance
+
+- Registered MCP calls match the existing UI contract for every eligible field, including explicit empties and domain-specific errors.
+- Unauthorized, invalid, and conflicting changes preserve invariants without partial writes or sensitive output. New atomic patches cover competing writers.
+- Clean editors update live and survive reload. Dirty drafts survive until recovery, on desktop and phone.
+
+## Verification
+
+Run from the repository root after the one-time workspace dependency install in Task 00.
+These new test paths and names are planned implementation outputs, not existing evidence.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/prompts/controller ./internal/prompts/service ./internal/prompts/catalog ./internal/mcp/server ./internal/mcp/handlers
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk pnpm --dir apps/web exec vitest run lib/settings-discovery/prompt-settings-contract.test.ts components/settings/prompt-settings-reconciliation.test.tsx
+rtk pnpm --dir apps/web run typecheck
+rtk pnpm --dir apps/web run i18n:check
+rtk pnpm --dir apps/web e2e:run --project chromium tests/settings/prompt-settings-mcp.spec.ts
+rtk pnpm --dir apps/web e2e:run --project mobile-chrome tests/settings/mobile-prompt-settings-mcp.spec.ts
+rtk node scripts/validate-public-docs.mjs
+rtk git diff --check
+```
+
+Add `TestPromptSettingsParity` and `TestPromptSettingsAuthority` in
+`apps/backend/internal/mcp/server/settings_prompt_settings_test.go`.
+Use real registered tools plus domain fixtures, not only direct handler invocation.
+Add domain tests for any changed persistence path, including rollback and concurrent updates.
+When a SQL query changes, include SQLite/PostgreSQL behavior evidence under the existing domain test conventions.
+
+## E2E scenario
+
+Create and update a disposable prompt, observe its editor, reload, and preserve an unsaved competing draft.
+Use disposable resources and mock providers. Restore user-level settings in cleanup, including after failures.
+Run desktop and phone separately with the managed runner and record discovered test counts.
+
+## Files likely touched
+
+- `apps/backend/internal/prompts/dto/dto.go`
+- `apps/backend/internal/prompts/controller/controller.go`
+- `apps/backend/internal/prompts/service/`
+- `apps/backend/internal/prompts/catalog/ (new)`
+- `apps/web/components/settings/prompts-settings.tsx`
+- `apps/backend/internal/backendapp/services.go` and MCP handler composition.
+- `apps/backend/internal/mcp/server/settings_prompt_settings_test.go` (new).
+- `apps/web/lib/settings-discovery/prompt-settings-contract.test.ts` (new).
+- `apps/web/components/settings/prompt-settings-reconciliation.test.tsx` (new): clean updates, dirty conflicts, own acknowledgements, and late replies.
+- `apps/web/lib/settings-discovery/coverage-inventory.ts` and generated snapshots.
+- Relevant domain store subscriptions, current editor state, and locale catalogs.
+- The two E2E files named in Verification.
+
+## Dependencies
+
+Task 09 completes the preceding slice.
+Tasks 00 through 04 establish inventory, schemas, generic tools, and draft-recovery behavior.
+The sequential order avoids conflicts in shared composition and generated snapshots.
+
+## Risks
+
+- Prompt bodies are untrusted user data and can contain credentials. Metadata search must not inspect them.
+- Saved settings and active runtime state can differ. Responses must not claim an unobserved runtime change.
+- Missing identity can look like an internal service caller. MCP must reject that case under enforced authentication.
+
+## Mobile contract
+
+Reuse the current domain settings route, shared save contributor, and existing phone composition.
+Keep recovery inline with the existing discard action, one content scroll owner, and safe-area-aware controls.
+Prove touch access and no horizontal page overflow. No new modal or breakpoint layout is required.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- Both system designs, especially Required domains, Mutation semantics, Relationships, and Visible results.
+- Task 00's field inventory and each source contract listed above.
+- Existing domain tests, profile parity tests, and nearby shipped settings E2E.
+- Scoped AGENTS.md, /tdd, /mobile-parity, /e2e, and /docs-maintainer before implementation.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Registered saved prompt settings and routed supported values through the existing domain path.
+- Preserved prompt ownership and content validation boundaries.
+- Covered prompt descriptors and adapter behavior in the focused backend suite.
diff --git a/docs/plans/agent-settings-parity/task-11-utility-settings.md b/docs/plans/agent-settings-parity/task-11-utility-settings.md
new file mode 100644
index 0000000000..8e52acae78
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-11-utility-settings.md
@@ -0,0 +1,160 @@
+---
+id: "11-utility-settings"
+title: "Expose utility agent settings"
+status: done
+wave: 11
+depends_on:
+ - "10-prompt-settings"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-006.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.4
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+---
+
+# Task 11: Expose utility agent settings
+
+## Summary
+
+Deliver the domain through the shared settings tools and authorized resource lookup.
+Include its complete eligible field set, current UI result, and independent contract checks.
+
+## In scope
+
+- Adopt utility names, prompts, enabled state, and canonical agent-profile bindings.
+- Preserve built-in restrictions and dependency validation. Do not promote legacy agent/model migration inputs into new controls.
+- Add an explicit create_utility_agent_kandev adapter if missing, with a stable settings envelope.
+- Use profile discovery for authorized compatible choices and retain failure states.
+- Reconcile utility drafts without executing utility prompts as part of settings validation.
+- Register metadata, context schemas, typed updates, redacted reads, and authorized lookup in the production composition.
+- Add domain aliases to the independent search-query suite and update the generated snapshots.
+- Include shared DTO conversion, semantic validation, and required atomic patch behavior for every write interface.
+- Use current domain events, or add scoped value-free invalidation when none exists.
+- Add coverage bindings and scoped editor tests. Update `docs/public/agents-and-profiles.md` with delivered behavior.
+
+## Out of scope
+
+- New persistence owners, arbitrary database access, privilege changes, and unrelated lifecycle operations.
+- Automatic merging of dirty drafts, new navigation layouts, and real provider credentials in tests.
+
+## Acceptance
+
+- Registered MCP calls match the existing UI contract for every eligible field, including explicit empties and domain-specific errors.
+- Unauthorized, invalid, and conflicting changes preserve invariants without partial writes or sensitive output. New atomic patches cover competing writers.
+- Clean editors update live and survive reload. Dirty drafts survive until recovery, on desktop and phone.
+
+## Verification
+
+Run from the repository root after the one-time workspace dependency install in Task 00.
+These new test paths and names are planned implementation outputs, not existing evidence.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/utility/controller ./internal/utility/service ./internal/utility/profilebinding ./internal/utility/catalog ./internal/mcp/server ./internal/mcp/handlers
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk pnpm --dir apps/web exec vitest run lib/settings-discovery/utility-settings-contract.test.ts components/settings/utility-settings-reconciliation.test.tsx
+rtk pnpm --dir apps/web run typecheck
+rtk pnpm --dir apps/web run i18n:check
+rtk pnpm --dir apps/web e2e:run --project chromium tests/settings/utility-settings-mcp.spec.ts
+rtk pnpm --dir apps/web e2e:run --project mobile-chrome tests/settings/mobile-utility-settings-mcp.spec.ts
+rtk node scripts/validate-public-docs.mjs
+rtk git diff --check
+```
+
+Add `TestUtilitySettingsParity` and `TestUtilitySettingsAuthority` in
+`apps/backend/internal/mcp/server/settings_utility_settings_test.go`.
+Use real registered tools plus domain fixtures, not only direct handler invocation.
+Add domain tests for any changed persistence path, including rollback and concurrent updates.
+When a SQL query changes, include SQLite/PostgreSQL behavior evidence under the existing domain test conventions.
+
+## E2E scenario
+
+Create a disposable utility, select its profile through MCP, observe the settings page, and reject an invalid binding.
+Use disposable resources and mock providers. Restore user-level settings in cleanup, including after failures.
+Run desktop and phone separately with the managed runner and record discovered test counts.
+
+## Files likely touched
+
+- `apps/backend/internal/utility/dto/dto.go`
+- `apps/backend/internal/utility/controller/controller.go`
+- `apps/backend/internal/utility/service/service.go`
+- `apps/backend/internal/utility/profilebinding/`
+- `apps/backend/internal/utility/catalog/ (new)`
+- `apps/web/components/settings/utility-agents-section-save.test.tsx`
+- `apps/backend/internal/backendapp/services.go` and MCP handler composition.
+- `apps/backend/internal/mcp/server/settings_utility_settings_test.go` (new).
+- `apps/web/lib/settings-discovery/utility-settings-contract.test.ts` (new).
+- `apps/web/components/settings/utility-settings-reconciliation.test.tsx` (new): clean updates, dirty conflicts, own acknowledgements, and late replies.
+- `apps/web/lib/settings-discovery/coverage-inventory.ts` and generated snapshots.
+- Relevant domain store subscriptions, current editor state, and locale catalogs.
+- The two E2E files named in Verification.
+
+## Dependencies
+
+Task 10 completes the preceding slice.
+Tasks 00 through 04 establish inventory, schemas, generic tools, and draft-recovery behavior.
+The sequential order avoids conflicts in shared composition and generated snapshots.
+
+## Risks
+
+- Updating profile bindings must not bypass the utility dependency resolver or overwrite personal utility defaults.
+- Saved settings and active runtime state can differ. Responses must not claim an unobserved runtime change.
+- Missing identity can look like an internal service caller. MCP must reject that case under enforced authentication.
+
+## Mobile contract
+
+Reuse the current domain settings route, shared save contributor, and existing phone composition.
+Keep recovery inline with the existing discard action, one content scroll owner, and safe-area-aware controls.
+Prove touch access and no horizontal page overflow. No new modal or breakpoint layout is required.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- Both system designs, especially Required domains, Mutation semantics, Relationships, and Visible results.
+- Task 00's field inventory and each source contract listed above.
+- Existing domain tests, profile parity tests, and nearby shipped settings E2E.
+- Scoped AGENTS.md, /tdd, /mobile-parity, /e2e, and /docs-maintainer before implementation.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Registered utility agent settings and their supported configuration fields.
+- Preserved utility-agent ownership and computed/action boundaries.
+- Covered utility descriptors and adapter behavior in the focused backend suite.
diff --git a/docs/plans/agent-settings-parity/task-12-editor-settings.md b/docs/plans/agent-settings-parity/task-12-editor-settings.md
new file mode 100644
index 0000000000..d5c663bd05
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-12-editor-settings.md
@@ -0,0 +1,159 @@
+---
+id: "12-editor-settings"
+title: "Expose editor definition settings"
+status: done
+wave: 12
+depends_on:
+ - "11-utility-settings"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-006.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.4
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+---
+
+# Task 12: Expose editor definition settings
+
+## Summary
+
+Deliver the domain through the shared settings tools and authorized resource lookup.
+Include its complete eligible field set, current UI result, and independent contract checks.
+
+## In scope
+
+- Adopt saved editor definitions with kind-specific schemas for opaque configuration.
+- Keep installed status and discovery results read-only. Default editor selection stays in user settings.
+- Add an explicit create_editor_kandev adapter if missing, with a validated settings envelope.
+- Preserve built-in editor restrictions and supported command/URL configuration rules.
+- Reconcile the terminal/editor settings surface without opening applications or executing commands.
+- Register metadata, context schemas, typed updates, redacted reads, and authorized lookup in the production composition.
+- Add domain aliases to the independent search-query suite and update the generated snapshots.
+- Include shared DTO conversion, semantic validation, and required atomic patch behavior for every write interface.
+- Use current domain events, or add scoped value-free invalidation when none exists.
+- Add coverage bindings and scoped editor tests. Update `docs/public/automation-and-mcp.md` with delivered behavior.
+
+## Out of scope
+
+- New persistence owners, arbitrary database access, privilege changes, and unrelated lifecycle operations.
+- Automatic merging of dirty drafts, new navigation layouts, and real provider credentials in tests.
+
+## Acceptance
+
+- Registered MCP calls match the existing UI contract for every eligible field, including explicit empties and domain-specific errors.
+- Unauthorized, invalid, and conflicting changes preserve invariants without partial writes or sensitive output. New atomic patches cover competing writers.
+- Clean editors update live and survive reload. Dirty drafts survive until recovery, on desktop and phone.
+
+## Verification
+
+Run from the repository root after the one-time workspace dependency install in Task 00.
+These new test paths and names are planned implementation outputs, not existing evidence.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/editors/controller ./internal/editors/service ./internal/editors/catalog ./internal/mcp/server ./internal/mcp/handlers
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk pnpm --dir apps/web exec vitest run lib/settings-discovery/editor-settings-contract.test.ts components/settings/editor-settings-reconciliation.test.tsx
+rtk pnpm --dir apps/web run typecheck
+rtk pnpm --dir apps/web run i18n:check
+rtk pnpm --dir apps/web e2e:run --project chromium tests/settings/editor-settings-mcp.spec.ts
+rtk pnpm --dir apps/web e2e:run --project mobile-chrome tests/settings/mobile-editor-settings-mcp.spec.ts
+rtk node scripts/validate-public-docs.mjs
+rtk git diff --check
+```
+
+Add `TestEditorSettingsParity` and `TestEditorSettingsAuthority` in
+`apps/backend/internal/mcp/server/settings_editor_settings_test.go`.
+Use real registered tools plus domain fixtures, not only direct handler invocation.
+Add domain tests for any changed persistence path, including rollback and concurrent updates.
+When a SQL query changes, include SQLite/PostgreSQL behavior evidence under the existing domain test conventions.
+
+## E2E scenario
+
+Create a disposable editor definition, change its saved settings, and verify the visible result without launching it.
+Use disposable resources and mock providers. Restore user-level settings in cleanup, including after failures.
+Run desktop and phone separately with the managed runner and record discovered test counts.
+
+## Files likely touched
+
+- `apps/backend/internal/editors/dto/dto.go`
+- `apps/backend/internal/editors/controller/controller.go`
+- `apps/backend/internal/editors/service/service.go`
+- `apps/backend/internal/editors/catalog/ (new)`
+- `apps/web/lib/settings-discovery/catalog/preferences.ts`
+- `apps/backend/internal/backendapp/services.go` and MCP handler composition.
+- `apps/backend/internal/mcp/server/settings_editor_settings_test.go` (new).
+- `apps/web/lib/settings-discovery/editor-settings-contract.test.ts` (new).
+- `apps/web/components/settings/editor-settings-reconciliation.test.tsx` (new): clean updates, dirty conflicts, own acknowledgements, and late replies.
+- `apps/web/lib/settings-discovery/coverage-inventory.ts` and generated snapshots.
+- Relevant domain store subscriptions, current editor state, and locale catalogs.
+- The two E2E files named in Verification.
+
+## Dependencies
+
+Task 11 completes the preceding slice.
+Tasks 00 through 04 establish inventory, schemas, generic tools, and draft-recovery behavior.
+The sequential order avoids conflicts in shared composition and generated snapshots.
+
+## Risks
+
+- Saving an editor definition must not become an arbitrary command-execution operation.
+- Saved settings and active runtime state can differ. Responses must not claim an unobserved runtime change.
+- Missing identity can look like an internal service caller. MCP must reject that case under enforced authentication.
+
+## Mobile contract
+
+Reuse the current domain settings route, shared save contributor, and existing phone composition.
+Keep recovery inline with the existing discard action, one content scroll owner, and safe-area-aware controls.
+Prove touch access and no horizontal page overflow. No new modal or breakpoint layout is required.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- Both system designs, especially Required domains, Mutation semantics, Relationships, and Visible results.
+- Task 00's field inventory and each source contract listed above.
+- Existing domain tests, profile parity tests, and nearby shipped settings E2E.
+- Scoped AGENTS.md, /tdd, /mobile-parity, /e2e, and /docs-maintainer before implementation.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Registered editor definitions and routed supported values through the existing editor domain.
+- Preserved executable/lifecycle boundaries and sensitive configuration handling.
+- Covered editor descriptors and adapter behavior in the focused backend suite.
diff --git a/docs/plans/agent-settings-parity/task-13-notification-settings.md b/docs/plans/agent-settings-parity/task-13-notification-settings.md
new file mode 100644
index 0000000000..f25f216c27
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-13-notification-settings.md
@@ -0,0 +1,160 @@
+---
+id: "13-notification-settings"
+title: "Expose notification provider settings"
+status: done
+wave: 13
+depends_on:
+ - "12-editor-settings"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-006.7
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.4
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+---
+
+# Task 13: Expose notification provider settings
+
+## Summary
+
+Deliver the domain through the shared settings tools and authorized resource lookup.
+Include its complete eligible field set, current UI result, and independent contract checks.
+
+## In scope
+
+- Adopt provider names, enabled state, typed provider configuration, and event subscriptions.
+- Preserve per-user ownership and validate the complete patch before persisting provider/event changes.
+- Preserve credential-bearing fields on omission. New reads redact them and never resolve credentials for descriptions.
+- Add an explicit create_notification_provider_kandev adapter if missing. Creation does not send a test notification.
+- Reconcile the provider editor and report unavailable provider capabilities without dropping metadata.
+- Register metadata, context schemas, typed updates, redacted reads, and authorized lookup in the production composition.
+- Add domain aliases to the independent search-query suite and update the generated snapshots.
+- Include shared DTO conversion, semantic validation, and required atomic patch behavior for every write interface.
+- Use current domain events, or add scoped value-free invalidation when none exists.
+- Add coverage bindings and scoped editor tests. Update `docs/public/automation-and-mcp.md` with delivered behavior.
+
+## Out of scope
+
+- New persistence owners, arbitrary database access, privilege changes, and unrelated lifecycle operations.
+- Automatic merging of dirty drafts, new navigation layouts, and real provider credentials in tests.
+
+## Acceptance
+
+- Registered MCP calls match the existing UI contract for every eligible field, including explicit empties and domain-specific errors.
+- Unauthorized, invalid, and conflicting changes preserve invariants without partial writes or sensitive output. New atomic patches cover competing writers.
+- Clean editors update live and survive reload. Dirty drafts survive until recovery, on desktop and phone.
+
+## Verification
+
+Run from the repository root after the one-time workspace dependency install in Task 00.
+These new test paths and names are planned implementation outputs, not existing evidence.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/notifications/controller ./internal/notifications/service ./internal/notifications/catalog ./internal/mcp/server ./internal/mcp/handlers
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk pnpm --dir apps/web exec vitest run lib/settings-discovery/notification-settings-contract.test.ts components/settings/notification-settings-reconciliation.test.tsx
+rtk pnpm --dir apps/web run typecheck
+rtk pnpm --dir apps/web run i18n:check
+rtk pnpm --dir apps/web e2e:run --project chromium tests/settings/notification-settings-mcp.spec.ts
+rtk pnpm --dir apps/web e2e:run --project mobile-chrome tests/settings/mobile-notification-settings-mcp.spec.ts
+rtk node scripts/validate-public-docs.mjs
+rtk git diff --check
+```
+
+Add `TestNotificationSettingsParity` and `TestNotificationSettingsAuthority` in
+`apps/backend/internal/mcp/server/settings_notification_settings_test.go`.
+Use real registered tools plus domain fixtures, not only direct handler invocation.
+Add domain tests for any changed persistence path, including rollback and concurrent updates.
+When a SQL query changes, include SQLite/PostgreSQL behavior evidence under the existing domain test conventions.
+
+## E2E scenario
+
+Change event subscriptions on a disposable provider, verify another user's provider is invisible, and observe reload persistence.
+Use disposable resources and mock providers. Restore user-level settings in cleanup, including after failures.
+Run desktop and phone separately with the managed runner and record discovered test counts.
+
+## Files likely touched
+
+- `apps/backend/internal/notifications/dto/dto.go`
+- `apps/backend/internal/notifications/controller/controller.go`
+- `apps/backend/internal/notifications/service/service.go`
+- `apps/backend/internal/notifications/catalog/ (new)`
+- `apps/web/components/settings/notifications-settings-actions.ts`
+- `apps/web/components/settings/notifications-settings.tsx`
+- `apps/backend/internal/backendapp/services.go` and MCP handler composition.
+- `apps/backend/internal/mcp/server/settings_notification_settings_test.go` (new).
+- `apps/web/lib/settings-discovery/notification-settings-contract.test.ts` (new).
+- `apps/web/components/settings/notification-settings-reconciliation.test.tsx` (new): clean updates, dirty conflicts, own acknowledgements, and late replies.
+- `apps/web/lib/settings-discovery/coverage-inventory.ts` and generated snapshots.
+- Relevant domain store subscriptions, current editor state, and locale catalogs.
+- The two E2E files named in Verification.
+
+## Dependencies
+
+Task 12 completes the preceding slice.
+Tasks 00 through 04 establish inventory, schemas, generic tools, and draft-recovery behavior.
+The sequential order avoids conflicts in shared composition and generated snapshots.
+
+## Risks
+
+- Provider configuration can contain secret URLs. Subscription writes must not partially commit an invalid provider patch.
+- Saved settings and active runtime state can differ. Responses must not claim an unobserved runtime change.
+- Missing identity can look like an internal service caller. MCP must reject that case under enforced authentication.
+
+## Mobile contract
+
+Reuse the current domain settings route, shared save contributor, and existing phone composition.
+Keep recovery inline with the existing discard action, one content scroll owner, and safe-area-aware controls.
+Prove touch access and no horizontal page overflow. No new modal or breakpoint layout is required.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- Both system designs, especially Required domains, Mutation semantics, Relationships, and Visible results.
+- Task 00's field inventory and each source contract listed above.
+- Existing domain tests, profile parity tests, and nearby shipped settings E2E.
+- Scoped AGENTS.md, /tdd, /mobile-parity, /e2e, and /docs-maintainer before implementation.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Registered notification provider settings with explicit sensitive-field handling.
+- Preserved provider lifecycle and credential-enrollment boundaries.
+- Covered notification descriptors, redaction, and adapter behavior in the focused backend suite.
diff --git a/docs/plans/agent-settings-parity/task-14-issue-integration-settings.md b/docs/plans/agent-settings-parity/task-14-issue-integration-settings.md
new file mode 100644
index 0000000000..6f5cb8cba4
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-14-issue-integration-settings.md
@@ -0,0 +1,162 @@
+---
+id: "14-issue-integration-settings"
+title: "Expose issue integration settings"
+status: done
+wave: 14
+depends_on:
+ - "13-notification-settings"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-006.8
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.3
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+---
+
+# Task 14: Expose issue integration settings
+
+## Summary
+
+Deliver the domain through the shared settings tools and authorized resource lookup.
+Include its complete eligible field set, current UI result, and independent contract checks.
+
+## In scope
+
+- Adopt noncredential Jira and Linear defaults plus existing Sentry instance settings and all eligible watch fields.
+- Preserve workspace ownership and Sentry instance identity. Do not select a singleton when several instances exist.
+- Reuse credential-preserving domain paths. Enrollment and credential-bearing connection identity changes remain interactive-only.
+- Validate watch workflow/profile/instance references, schedules, and feature availability before saving.
+- Retain existing cache invalidation and background health behavior. Report post-save probe failure as degraded status, not rollback.
+- Reconcile integration forms and watch editors using scoped events or invalidation.
+- Register metadata, context schemas, typed updates, redacted reads, and authorized lookup in the production composition.
+- Add domain aliases to the independent search-query suite and update the generated snapshots.
+- Include shared DTO conversion, semantic validation, and required atomic patch behavior for every write interface.
+- Use current domain events, or add scoped value-free invalidation when none exists.
+- Add coverage bindings and scoped editor tests. Update `docs/public/automation-and-mcp.md` with delivered behavior.
+
+## Out of scope
+
+- New persistence owners, arbitrary database access, privilege changes, and unrelated lifecycle operations.
+- Automatic merging of dirty drafts, new navigation layouts, and real provider credentials in tests.
+
+## Acceptance
+
+- Registered MCP calls match the existing UI contract for every eligible field, including explicit empties and domain-specific errors.
+- Unauthorized, invalid, and conflicting changes preserve invariants without partial writes or sensitive output. New atomic patches cover competing writers.
+- Clean editors update live and survive reload. Dirty drafts survive until recovery, on desktop and phone.
+
+## Verification
+
+Run from the repository root after the one-time workspace dependency install in Task 00.
+These new test paths and names are planned implementation outputs, not existing evidence.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/jira ./internal/linear ./internal/sentry ./internal/mcp/server ./internal/mcp/handlers
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk pnpm --dir apps/web exec vitest run lib/settings-discovery/issue-integration-settings-contract.test.ts components/settings/issue-integration-settings-reconciliation.test.tsx
+rtk pnpm --dir apps/web run typecheck
+rtk pnpm --dir apps/web run i18n:check
+rtk pnpm --dir apps/web e2e:run --project chromium tests/settings/issue-integration-settings-mcp.spec.ts
+rtk pnpm --dir apps/web e2e:run --project mobile-chrome tests/settings/mobile-issue-integration-settings-mcp.spec.ts
+rtk node scripts/validate-public-docs.mjs
+rtk git diff --check
+```
+
+Add `TestIssueIntegrationSettingsParity` and `TestIssueIntegrationSettingsAuthority` in
+`apps/backend/internal/mcp/server/settings_issue_integration_settings_test.go`.
+Use real registered tools plus domain fixtures, not only direct handler invocation.
+Add domain tests for any changed persistence path, including rollback and concurrent updates.
+When a SQL query changes, include SQLite/PostgreSQL behavior evidence under the existing domain test conventions.
+
+## E2E scenario
+
+Update one fixture per provider, observe each settings/watch surface, and reject a foreign workspace or Sentry instance.
+Use disposable resources and mock providers. Restore user-level settings in cleanup, including after failures.
+Run desktop and phone separately with the managed runner and record discovered test counts.
+
+## Files likely touched
+
+- `apps/backend/internal/jira/models.go`
+- `apps/backend/internal/jira/service.go`
+- `apps/backend/internal/linear/models.go`
+- `apps/backend/internal/linear/service.go`
+- `apps/backend/internal/sentry/models.go`
+- `apps/backend/internal/sentry/service.go`
+- `apps/backend/internal/{jira,linear,sentry}/settings_catalog.go (new)`
+- `apps/web/app/settings/integrations/`
+- `apps/backend/internal/backendapp/services.go` and MCP handler composition.
+- `apps/backend/internal/mcp/server/settings_issue_integration_settings_test.go` (new).
+- `apps/web/lib/settings-discovery/issue-integration-settings-contract.test.ts` (new).
+- `apps/web/components/settings/issue-integration-settings-reconciliation.test.tsx` (new): clean updates, dirty conflicts, own acknowledgements, and late replies.
+- `apps/web/lib/settings-discovery/coverage-inventory.ts` and generated snapshots.
+- Relevant domain store subscriptions, current editor state, and locale catalogs.
+- The two E2E files named in Verification.
+
+## Dependencies
+
+Task 13 completes the preceding slice.
+Tasks 00 through 04 establish inventory, schemas, generic tools, and draft-recovery behavior.
+The sequential order avoids conflicts in shared composition and generated snapshots.
+
+## Risks
+
+- Legacy full-document setters can erase omitted values. Shared domain atomic patches or complete-document semantics must protect every writer.
+- Saved settings and active runtime state can differ. Responses must not claim an unobserved runtime change.
+- Missing identity can look like an internal service caller. MCP must reject that case under enforced authentication.
+
+## Mobile contract
+
+Reuse the current domain settings route, shared save contributor, and existing phone composition.
+Keep recovery inline with the existing discard action, one content scroll owner, and safe-area-aware controls.
+Prove touch access and no horizontal page overflow. No new modal or breakpoint layout is required.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- Both system designs, especially Required domains, Mutation semantics, Relationships, and Visible results.
+- Task 00's field inventory and each source contract listed above.
+- Existing domain tests, profile parity tests, and nearby shipped settings E2E.
+- Scoped AGENTS.md, /tdd, /mobile-parity, /e2e, and /docs-maintainer before implementation.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Registered Jira, Linear, Sentry instance, and issue-watch settings.
+- Routed noncredential fields through provider-owned integration services with workspace authorization.
+- Preserved connection and secret-enrollment exceptions and covered provider adapters in backend tests.
diff --git a/docs/plans/agent-settings-parity/task-15-codehost-settings.md b/docs/plans/agent-settings-parity/task-15-codehost-settings.md
new file mode 100644
index 0000000000..0506ac2e27
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-15-codehost-settings.md
@@ -0,0 +1,161 @@
+---
+id: "15-codehost-settings"
+title: "Expose code-host integration settings"
+status: done
+wave: 15
+depends_on:
+ - "14-issue-integration-settings"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-006.8
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.3
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+---
+
+# Task 15: Expose code-host integration settings
+
+## Summary
+
+Deliver the domain through the shared settings tools and authorized resource lookup.
+Include its complete eligible field set, current UI result, and independent contract checks.
+
+## In scope
+
+- Adopt GitHub, GitLab, and Azure DevOps workspace defaults, repository scope, presets, and watch configuration.
+- Keep personal saved-query preferences in user settings and provider workspace settings in their domain.
+- Preserve credential generation, provider-host identity, repository scope, and authorized watch references.
+- Exclude account enrollment, token operations, remote issue/PR mutations, and immediate watch execution.
+- Retain domain cache/event behavior and reconcile each provider's settings and watch editor.
+- Register metadata, context schemas, typed updates, redacted reads, and authorized lookup in the production composition.
+- Add domain aliases to the independent search-query suite and update the generated snapshots.
+- Include shared DTO conversion, semantic validation, and required atomic patch behavior for every write interface.
+- Use current domain events, or add scoped value-free invalidation when none exists.
+- Add coverage bindings and scoped editor tests. Update `docs/public/automation-and-mcp.md` with delivered behavior.
+
+## Out of scope
+
+- New persistence owners, arbitrary database access, privilege changes, and unrelated lifecycle operations.
+- Automatic merging of dirty drafts, new navigation layouts, and real provider credentials in tests.
+
+## Acceptance
+
+- Registered MCP calls match the existing UI contract for every eligible field, including explicit empties and domain-specific errors.
+- Unauthorized, invalid, and conflicting changes preserve invariants without partial writes or sensitive output. New atomic patches cover competing writers.
+- Clean editors update live and survive reload. Dirty drafts survive until recovery, on desktop and phone.
+
+## Verification
+
+Run from the repository root after the one-time workspace dependency install in Task 00.
+These new test paths and names are planned implementation outputs, not existing evidence.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/github ./internal/gitlab ./internal/azuredevops ./internal/mcp/server ./internal/mcp/handlers
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk pnpm --dir apps/web exec vitest run lib/settings-discovery/codehost-settings-contract.test.ts components/settings/codehost-settings-reconciliation.test.tsx
+rtk pnpm --dir apps/web run typecheck
+rtk pnpm --dir apps/web run i18n:check
+rtk pnpm --dir apps/web e2e:run --project chromium tests/settings/codehost-settings-mcp.spec.ts
+rtk pnpm --dir apps/web e2e:run --project mobile-chrome tests/settings/mobile-codehost-settings-mcp.spec.ts
+rtk node scripts/validate-public-docs.mjs
+rtk git diff --check
+```
+
+Add `TestCodeHostSettingsParity` and `TestCodeHostSettingsAuthority` in
+`apps/backend/internal/mcp/server/settings_codehost_settings_test.go`.
+Use real registered tools plus domain fixtures, not only direct handler invocation.
+Add domain tests for any changed persistence path, including rollback and concurrent updates.
+When a SQL query changes, include SQLite/PostgreSQL behavior evidence under the existing domain test conventions.
+
+## E2E scenario
+
+Update a scope or preset and a watch fixture for each provider, observe the UI, and prove cross-workspace isolation.
+Use disposable resources and mock providers. Restore user-level settings in cleanup, including after failures.
+Run desktop and phone separately with the managed runner and record discovered test counts.
+
+## Files likely touched
+
+- `apps/backend/internal/github/workspace_settings_service.go`
+- `apps/backend/internal/github/models.go`
+- `apps/backend/internal/gitlab/service_config.go`
+- `apps/backend/internal/gitlab/watch_models.go`
+- `apps/backend/internal/azuredevops/workspace_settings.go`
+- `apps/backend/internal/azuredevops/watch_service.go`
+- `apps/backend/internal/{github,gitlab,azuredevops}/settings_catalog.go (new)`
+- `apps/web/app/settings/integrations/`
+- `apps/backend/internal/backendapp/services.go` and MCP handler composition.
+- `apps/backend/internal/mcp/server/settings_codehost_settings_test.go` (new).
+- `apps/web/lib/settings-discovery/codehost-settings-contract.test.ts` (new).
+- `apps/web/components/settings/codehost-settings-reconciliation.test.tsx` (new): clean updates, dirty conflicts, own acknowledgements, and late replies.
+- `apps/web/lib/settings-discovery/coverage-inventory.ts` and generated snapshots.
+- Relevant domain store subscriptions, current editor state, and locale catalogs.
+- The two E2E files named in Verification.
+
+## Dependencies
+
+Task 14 completes the preceding slice.
+Tasks 00 through 04 establish inventory, schemas, generic tools, and draft-recovery behavior.
+The sequential order avoids conflicts in shared composition and generated snapshots.
+
+## Risks
+
+- Provider identity and workspace scope are authorization boundaries. A settings update cannot borrow another workspace's credential context.
+- Saved settings and active runtime state can differ. Responses must not claim an unobserved runtime change.
+- Missing identity can look like an internal service caller. MCP must reject that case under enforced authentication.
+
+## Mobile contract
+
+Reuse the current domain settings route, shared save contributor, and existing phone composition.
+Keep recovery inline with the existing discard action, one content scroll owner, and safe-area-aware controls.
+Prove touch access and no horizontal page overflow. No new modal or breakpoint layout is required.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- Both system designs, especially Required domains, Mutation semantics, Relationships, and Visible results.
+- Task 00's field inventory and each source contract listed above.
+- Existing domain tests, profile parity tests, and nearby shipped settings E2E.
+- Scoped AGENTS.md, /tdd, /mobile-parity, /e2e, and /docs-maintainer before implementation.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Registered GitHub, GitLab, Azure DevOps, and code-host watch settings.
+- Routed noncredential fields through provider-owned integration services with workspace authorization.
+- Preserved connection identity and secret boundaries and covered provider adapters in backend tests.
diff --git a/docs/plans/agent-settings-parity/task-16-automation-settings.md b/docs/plans/agent-settings-parity/task-16-automation-settings.md
new file mode 100644
index 0000000000..78b4a7bfd2
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-16-automation-settings.md
@@ -0,0 +1,158 @@
+---
+id: "16-automation-settings"
+title: "Expose workspace automation settings"
+status: done
+wave: 16
+depends_on:
+ - "15-codehost-settings"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-006.9
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.3
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+---
+
+# Task 16: Expose workspace automation settings
+
+## Summary
+
+Deliver the domain through the shared settings tools and authorized resource lookup.
+Include its complete eligible field set, current UI result, and independent contract checks.
+
+## In scope
+
+- Adopt existing automation definitions and trigger configuration through their service contracts.
+- Preserve workspace scoping, profile/workflow references, continuation limits, trigger types, and enablement gates.
+- Describe future scheduling effects. Do not run automations or alter run history through settings tools.
+- Keep webhook secrets redacted and require existing credential flows for enrollment.
+- Reconcile automation and trigger drafts on the current workspace settings route.
+- Register metadata, context schemas, typed updates, redacted reads, and authorized lookup in the production composition.
+- Add domain aliases to the independent search-query suite and update the generated snapshots.
+- Include shared DTO conversion, semantic validation, and required atomic patch behavior for every write interface.
+- Use current domain events, or add scoped value-free invalidation when none exists.
+- Add coverage bindings and scoped editor tests. Update `docs/public/automation-and-mcp.md` with delivered behavior.
+
+## Out of scope
+
+- New persistence owners, arbitrary database access, privilege changes, and unrelated lifecycle operations.
+- Automatic merging of dirty drafts, new navigation layouts, and real provider credentials in tests.
+
+## Acceptance
+
+- Registered MCP calls match the existing UI contract for every eligible field, including explicit empties and domain-specific errors.
+- Unauthorized, invalid, and conflicting changes preserve invariants without partial writes or sensitive output. New atomic patches cover competing writers.
+- Clean editors update live and survive reload. Dirty drafts survive until recovery, on desktop and phone.
+
+## Verification
+
+Run from the repository root after the one-time workspace dependency install in Task 00.
+These new test paths and names are planned implementation outputs, not existing evidence.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/automation ./internal/mcp/server ./internal/mcp/handlers
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk pnpm --dir apps/web exec vitest run lib/settings-discovery/automation-settings-contract.test.ts components/settings/automation-settings-reconciliation.test.tsx
+rtk pnpm --dir apps/web run typecheck
+rtk pnpm --dir apps/web run i18n:check
+rtk pnpm --dir apps/web e2e:run --project chromium tests/settings/automation-settings-mcp.spec.ts
+rtk pnpm --dir apps/web e2e:run --project mobile-chrome tests/settings/mobile-automation-settings-mcp.spec.ts
+rtk node scripts/validate-public-docs.mjs
+rtk git diff --check
+```
+
+Add `TestAutomationSettingsParity` and `TestAutomationSettingsAuthority` in
+`apps/backend/internal/mcp/server/settings_automation_settings_test.go`.
+Use real registered tools plus domain fixtures, not only direct handler invocation.
+Add domain tests for any changed persistence path, including rollback and concurrent updates.
+When a SQL query changes, include SQLite/PostgreSQL behavior evidence under the existing domain test conventions.
+
+## E2E scenario
+
+Change a disabled automation and trigger, observe its settings page, and reject invalid references without starting a run.
+Use disposable resources and mock providers. Restore user-level settings in cleanup, including after failures.
+Run desktop and phone separately with the managed runner and record discovered test counts.
+
+## Files likely touched
+
+- `apps/backend/internal/automation/models.go`
+- `apps/backend/internal/automation/service.go`
+- `apps/backend/internal/automation/handlers.go`
+- `apps/backend/internal/automation/settings_catalog.go (new)`
+- `apps/web/app/settings/workspace/[id]/automations/`
+- `apps/backend/internal/backendapp/services.go` and MCP handler composition.
+- `apps/backend/internal/mcp/server/settings_automation_settings_test.go` (new).
+- `apps/web/lib/settings-discovery/automation-settings-contract.test.ts` (new).
+- `apps/web/components/settings/automation-settings-reconciliation.test.tsx` (new): clean updates, dirty conflicts, own acknowledgements, and late replies.
+- `apps/web/lib/settings-discovery/coverage-inventory.ts` and generated snapshots.
+- Relevant domain store subscriptions, current editor state, and locale catalogs.
+- The two E2E files named in Verification.
+
+## Dependencies
+
+Task 15 completes the preceding slice.
+Tasks 00 through 04 establish inventory, schemas, generic tools, and draft-recovery behavior.
+The sequential order avoids conflicts in shared composition and generated snapshots.
+
+## Risks
+
+- Enabling a schedule changes future background work. A failed settings patch must not leave a half-updated trigger.
+- Saved settings and active runtime state can differ. Responses must not claim an unobserved runtime change.
+- Missing identity can look like an internal service caller. MCP must reject that case under enforced authentication.
+
+## Mobile contract
+
+Reuse the current domain settings route, shared save contributor, and existing phone composition.
+Keep recovery inline with the existing discard action, one content scroll owner, and safe-area-aware controls.
+Prove touch access and no horizontal page overflow. No new modal or breakpoint layout is required.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- Both system designs, especially Required domains, Mutation semantics, Relationships, and Visible results.
+- Task 00's field inventory and each source contract listed above.
+- Existing domain tests, profile parity tests, and nearby shipped settings E2E.
+- Scoped AGENTS.md, /tdd, /mobile-parity, /e2e, and /docs-maintainer before implementation.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Registered workspace automations and hydrated automation-trigger resources.
+- Preserved trigger relationships, workspace filtering, and sensitive configuration handling.
+- Covered automation reads, updates, and resource lookup in the focused backend suite.
diff --git a/docs/plans/agent-settings-parity/task-17-runtime-settings.md b/docs/plans/agent-settings-parity/task-17-runtime-settings.md
new file mode 100644
index 0000000000..c85c94a7e7
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-17-runtime-settings.md
@@ -0,0 +1,166 @@
+---
+id: "17-runtime-settings"
+title: "Expose permitted runtime overrides"
+status: done
+wave: 17
+depends_on:
+ - "16-automation-settings"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-006.10
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.5
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+---
+
+# Task 17: Expose permitted runtime overrides
+
+## Summary
+
+Deliver the domain through the shared settings tools and authorized resource lookup.
+Include its complete eligible field set, current UI result, and independent contract checks.
+
+## In scope
+
+- Derive runtime descriptors from the current flag registry and startup descriptors from the typed startup catalog.
+- Expose one runtime_flag resource per existing key, with boolean/null override semantics.
+- Enforce org.settings.manage before SetOverride. Preserve environment locks, mutability, retired identities, and pending-restart state.
+- Keep features.auth interactive-only and all deployment-owned startup settings read-only.
+- Preserve disabled-feature boundaries. Do not introduce a new flag, change shipped defaults, or restart the process.
+- Use the existing Feature Toggles UI for saved/active values and live invalidation.
+- Register metadata, context schemas, typed updates, redacted reads, and authorized lookup in the production composition.
+- Add domain aliases to the independent search-query suite and update the generated snapshots.
+- Include shared DTO conversion, semantic validation, and required atomic patch behavior for every write interface.
+- Use current domain events, or add scoped value-free invalidation when none exists.
+- Add coverage bindings and scoped editor tests. Update `docs/public/automation-and-mcp.md` with delivered behavior.
+
+## Out of scope
+
+- New persistence owners, arbitrary database access, privilege changes, and unrelated lifecycle operations.
+- Automatic merging of dirty drafts, new navigation layouts, and real provider credentials in tests.
+
+## Acceptance
+
+- Registered MCP calls match the existing UI contract for every eligible field, including explicit empties and domain-specific errors.
+- Unauthorized, invalid, and conflicting changes preserve invariants without partial writes or sensitive output. New atomic patches cover competing writers.
+- Clean editors update live and survive reload. Dirty drafts survive until recovery, on desktop and phone.
+
+## Verification
+
+Run from the repository root after the one-time workspace dependency install in Task 00.
+These new test paths and names are planned implementation outputs, not existing evidence.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/runtimeflags ./internal/common/config ./internal/profiles ./internal/mcp/server ./internal/mcp/handlers
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk make -C apps/backend lint
+rtk pnpm --dir apps/web exec vitest run lib/state/slices/features/features-contract.test.ts
+rtk pnpm --dir apps/web exec vitest run lib/settings-discovery/runtime-settings-contract.test.ts components/settings/runtime-settings-reconciliation.test.tsx
+rtk pnpm --dir apps/web run typecheck
+rtk pnpm --dir apps/web run lint
+rtk pnpm --dir apps/web run i18n:check
+rtk pnpm --dir apps/web e2e:run --project chromium tests/settings/runtime-settings-mcp.spec.ts
+rtk pnpm --dir apps/web e2e:run --project mobile-chrome tests/settings/mobile-runtime-settings-mcp.spec.ts
+rtk node scripts/validate-public-docs.mjs
+rtk git diff --check
+```
+
+Add `TestRuntimeSettingsParity` and `TestRuntimeSettingsAuthority` in
+`apps/backend/internal/mcp/server/settings_runtime_settings_test.go`.
+Use real registered tools plus domain fixtures, not only direct handler invocation.
+Add domain tests for any changed persistence path, including rollback and concurrent updates.
+When a SQL query changes, include SQLite/PostgreSQL behavior evidence under the existing domain test conventions.
+
+## E2E scenario
+
+Save and clear a permitted override, observe pending restart, and reject an environment-locked or authentication flag change.
+Use disposable resources and mock providers. Restore user-level settings in cleanup, including after failures.
+Run desktop and phone separately with the managed runner and record discovered test counts.
+
+## Files likely touched
+
+- `apps/backend/internal/runtimeflags/registry.go`
+- `apps/backend/internal/runtimeflags/service.go`
+- `apps/backend/internal/runtimeflags/handlers.go`
+- `apps/backend/internal/runtimeflags/settings_catalog.go (new)`
+- `apps/backend/internal/common/config/catalog.go`
+- `apps/web/lib/state/slices/features/`
+- `apps/backend/internal/backendapp/services.go` and MCP handler composition.
+- `apps/backend/internal/mcp/server/settings_runtime_settings_test.go` (new).
+- `apps/web/lib/settings-discovery/runtime-settings-contract.test.ts` (new).
+- `apps/web/components/settings/runtime-settings-reconciliation.test.tsx` (new): clean updates, dirty conflicts, own acknowledgements, and late replies.
+- `apps/web/lib/settings-discovery/coverage-inventory.ts` and generated snapshots.
+- Relevant domain store subscriptions, current editor state, and locale catalogs.
+- The two E2E files named in Verification.
+
+## Dependencies
+
+Task 16 completes the preceding slice.
+Tasks 00 through 04 establish inventory, schemas, generic tools, and draft-recovery behavior.
+The sequential order avoids conflicts in shared composition and generated snapshots.
+
+## Risks
+
+- The HTTP authorization guard does not run in MCP dispatch. A saved override is not proof that the running feature changed.
+- Saved settings and active runtime state can differ. Responses must not claim an unobserved runtime change.
+- Missing identity can look like an internal service caller. MCP must reject that case under enforced authentication.
+
+## Mobile contract
+
+Reuse the current domain settings route, shared save contributor, and existing phone composition.
+Keep recovery inline with the existing discard action, one content scroll owner, and safe-area-aware controls.
+Prove touch access and no horizontal page overflow. No new modal or breakpoint layout is required.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- Both system designs, especially Required domains, Mutation semantics, Relationships, and Visible results.
+- Task 00's field inventory and each source contract listed above.
+- Existing domain tests, profile parity tests, and nearby shipped settings E2E.
+- Scoped AGENTS.md, /tdd, /mobile-parity, /e2e, and /docs-maintainer before implementation.
+- /runtime-feature-flags. Existing identities and shipped defaults remain unchanged.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Registered permitted runtime overrides using the existing typed runtime-flag registry.
+- Preserved environment locks, explicit reset behavior, source provenance, and pending-restart state.
+- Covered the catalog `override` mapping and adapter behavior in backend tests.
diff --git a/docs/plans/agent-settings-parity/task-18-storage-settings.md b/docs/plans/agent-settings-parity/task-18-storage-settings.md
new file mode 100644
index 0000000000..88a8ea4191
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-18-storage-settings.md
@@ -0,0 +1,158 @@
+---
+id: "18-storage-settings"
+title: "Expose storage maintenance policies"
+status: done
+wave: 18
+depends_on:
+ - "17-runtime-settings"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-006.10
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-004.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-007.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-008.6
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.3
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+---
+
+# Task 18: Expose storage maintenance policies
+
+## Summary
+
+Deliver the domain through the shared settings tools and authorized resource lookup.
+Include its complete eligible field set, current UI result, and independent contract checks.
+
+## In scope
+
+- Expose the complete storage-maintenance settings document with replacement semantics.
+- Share the HTTP settings operation, authorization, and OnSettingsChanged callback with MCP.
+- Preserve exact dedicated-Docker acknowledgement and private Go-cache adoption restrictions.
+- Describe schedule/retention effects without starting cleanup, adopting paths, deleting quarantine, or restoring backups.
+- Reconcile the storage policy editor with value-free invalidation and dirty-draft recovery.
+- Register metadata, context schemas, typed updates, redacted reads, and authorized lookup in the production composition.
+- Add domain aliases to the independent search-query suite and update the generated snapshots.
+- Include shared DTO conversion, semantic validation, and required atomic patch behavior for every write interface.
+- Use current domain events, or add scoped value-free invalidation when none exists.
+- Add coverage bindings and scoped editor tests. Update `docs/public/automation-and-mcp.md` with delivered behavior.
+
+## Out of scope
+
+- New persistence owners, arbitrary database access, privilege changes, and unrelated lifecycle operations.
+- Automatic merging of dirty drafts, new navigation layouts, and real provider credentials in tests.
+
+## Acceptance
+
+- Registered MCP calls match the existing UI contract for every eligible field, including explicit empties and domain-specific errors.
+- Unauthorized, invalid, and conflicting changes preserve invariants without partial writes or sensitive output. New atomic patches cover competing writers.
+- Clean editors update live and survive reload. Dirty drafts survive until recovery, on desktop and phone.
+
+## Verification
+
+Run from the repository root after the one-time workspace dependency install in Task 00.
+These new test paths and names are planned implementation outputs, not existing evidence.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/system/storage ./internal/system/settings ./internal/mcp/server ./internal/mcp/handlers
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk pnpm --dir apps/web exec vitest run lib/settings-discovery/storage-settings-contract.test.ts components/settings/storage-settings-reconciliation.test.tsx
+rtk pnpm --dir apps/web run typecheck
+rtk pnpm --dir apps/web run i18n:check
+rtk pnpm --dir apps/web e2e:run --project chromium tests/settings/storage-settings-mcp.spec.ts
+rtk pnpm --dir apps/web e2e:run --project mobile-chrome tests/settings/mobile-storage-settings-mcp.spec.ts
+rtk node scripts/validate-public-docs.mjs
+rtk git diff --check
+```
+
+Add `TestStorageSettingsParity` and `TestStorageSettingsAuthority` in
+`apps/backend/internal/mcp/server/settings_storage_settings_test.go`.
+Use real registered tools plus domain fixtures, not only direct handler invocation.
+Add domain tests for any changed persistence path, including rollback and concurrent updates.
+When a SQL query changes, include SQLite/PostgreSQL behavior evidence under the existing domain test conventions.
+
+## E2E scenario
+
+Change a maintenance policy in an isolated fixture, observe it after reload, and reject unconfirmed dedicated-daemon or adoption changes.
+Use disposable resources and mock providers. Restore user-level settings in cleanup, including after failures.
+Run desktop and phone separately with the managed runner and record discovered test counts.
+
+## Files likely touched
+
+- `apps/backend/internal/system/storage/types.go`
+- `apps/backend/internal/system/storage/settings.go`
+- `apps/backend/internal/system/storage/handler.go`
+- `apps/backend/internal/system/storage/settings_catalog.go (new)`
+- `apps/web/lib/settings-discovery/catalog/system.ts`
+- `apps/backend/internal/backendapp/services.go` and MCP handler composition.
+- `apps/backend/internal/mcp/server/settings_storage_settings_test.go` (new).
+- `apps/web/lib/settings-discovery/storage-settings-contract.test.ts` (new).
+- `apps/web/components/settings/storage-settings-reconciliation.test.tsx` (new): clean updates, dirty conflicts, own acknowledgements, and late replies.
+- `apps/web/lib/settings-discovery/coverage-inventory.ts` and generated snapshots.
+- Relevant domain store subscriptions, current editor state, and locale catalogs.
+- The two E2E files named in Verification.
+
+## Dependencies
+
+Task 17 completes the preceding slice.
+Tasks 00 through 04 establish inventory, schemas, generic tools, and draft-recovery behavior.
+The sequential order avoids conflicts in shared composition and generated snapshots.
+
+## Risks
+
+- A generic force option must not authorize storage destruction or synthesize a required acknowledgement.
+- Saved settings and active runtime state can differ. Responses must not claim an unobserved runtime change.
+- Missing identity can look like an internal service caller. MCP must reject that case under enforced authentication.
+
+## Mobile contract
+
+Reuse the current domain settings route, shared save contributor, and existing phone composition.
+Keep recovery inline with the existing discard action, one content scroll owner, and safe-area-aware controls.
+Prove touch access and no horizontal page overflow. No new modal or breakpoint layout is required.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- Both system designs, especially Required domains, Mutation semantics, Relationships, and Visible results.
+- Task 00's field inventory and each source contract listed above.
+- Existing domain tests, profile parity tests, and nearby shipped settings E2E.
+- Scoped AGENTS.md, /tdd, /mobile-parity, /e2e, and /docs-maintainer before implementation.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Registered storage-maintenance policies through the existing complete-document settings service.
+- Preserved acknowledgement, scheduling, and no-immediate-maintenance boundaries.
+- Covered storage descriptors and adapter behavior in the focused backend suite.
diff --git a/docs/plans/agent-settings-parity/task-19-delivery-coverage.md b/docs/plans/agent-settings-parity/task-19-delivery-coverage.md
new file mode 100644
index 0000000000..1ee2c7cee7
--- /dev/null
+++ b/docs/plans/agent-settings-parity/task-19-delivery-coverage.md
@@ -0,0 +1,127 @@
+---
+id: "19-delivery-coverage"
+title: "Complete core settings coverage"
+status: done
+wave: 19
+depends_on:
+ - "18-storage-settings"
+plan: "plan.md"
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-001
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+acceptance_criteria:
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-001.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-001.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-006.11
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.1
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.2
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.3
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.4
+ - AC-PLATFORM-AGENT-SETTINGS-PARITY-009.5
+system_design:
+ - ../../specs/platform/system-design/agent-settings-parity.md
+ - ../../specs/platform/system-design/agent-settings-domains.md
+---
+
+# Task 19: Complete core settings coverage
+
+## Summary
+
+Close the required-domain inventory and prove the complete agent configuration workflow.
+Publish accurate guidance for the delivered tools, domains, and exceptions.
+
+## In scope
+
+- Reject pending eligible fields, missing domain adapters, unclassified controls, and stale generated snapshots.
+- Add negative fixtures for a new domain, route, nested field, removed descriptor, and weakened CI path filter.
+- Freeze the five shared tool envelopes. Prove an added setting changes discovery and validation without changing tool definitions.
+- Finish configuration-profile alias removal only for equivalent adopted operations. Retain external compatibility and explicit lifecycle tools.
+- Complete the cross-domain search corpus and configuration prompt examples.
+- Prove action boundaries, authentication exclusions, and explicit lookup from the assembled tool profile.
+- Update public tool coverage and domain guidance. Record exact supported/exception/pending counts from the independent inventory.
+
+## Out of scope
+
+- Generic QA, broad repository verification, unrelated cleanup, commits, pushes, or PR creation.
+- Relabeling an eligible missing field as an exception to pass the gate.
+
+## Acceptance
+
+- Every eligible field in the required domains has a working adapter and passing evidence. No required entry remains pending.
+- Shared tool schemas remain stable and all supported lifecycle calls remain compatible. Exceptions have reasons and recovery destinations.
+- The complete desktop/mobile flow succeeds through real MCP, visible UI state, and reload persistence. Public docs match actual coverage.
+
+## Verification
+
+Run from the repository root after the prior work-order checks pass.
+
+```bash
+rtk proxy go -C apps/backend test ./internal/settingscatalog ./internal/mcp/server ./internal/mcp/handlers ./internal/mcp/profile ./internal/backendapp
+rtk proxy go -C apps/backend run ./cmd/settings-catalog --check
+rtk node --test scripts/settings-contract-ci.test.mjs
+rtk pnpm --dir apps/web exec vitest run lib/settings-discovery/coverage-inventory.test.ts lib/settings-discovery/delivery-coverage.test.ts
+rtk pnpm --dir apps/web e2e:run --project chromium tests/settings/settings-agent-configuration.spec.ts
+rtk pnpm --dir apps/web e2e:run --project mobile-chrome tests/settings/mobile-settings-agent-configuration.spec.ts
+rtk node --test scripts/validate-public-docs.test.mjs
+rtk node scripts/validate-public-docs.mjs
+rtk python3 scripts/lint-spec-files.test.py
+rtk python3 scripts/lint-spec-files.py --all
+rtk git diff --check
+```
+
+Planned methods in `settings_delivery_test.go` are `TestRequiredSettingsCoverage`, `TestSettingsActionBoundaries`, and `TestStableSettingsToolDefinitions`.
+
+## E2E scenario
+
+Search for task behavior, identify the current user, and update archive confirmation.
+Find a disposable workflow and profile, then update a step binding through the compact tool.
+Update a repository setting and notification event subscription through their exact targets.
+Observe each page and reload it. Reject a wrong-workspace reference without changing state.
+Use isolated resources and restore personal settings after failure. No external accounts or real notifications are required.
+
+## Files likely touched
+
+- `apps/backend/internal/mcp/server/settings_delivery_test.go` (new).
+- `apps/backend/internal/settingscatalog/search_quality_test.go` and independent coverage tests.
+- `apps/backend/internal/mcp/server/server.go` and profile assembly tests.
+- `apps/backend/config/prompts/config-context.md`.
+- `apps/web/lib/settings-discovery/delivery-coverage.test.ts` (new).
+- `apps/web/lib/settings-discovery/coverage-inventory.ts` and generated snapshots.
+- The two E2E files named in Verification and their shared helper.
+- `scripts/settings-contract-ci.test.mjs` and existing CI workflows if a missing trigger is found.
+- `docs/public/automation-and-mcp.md`, `coverage.json`, and the affected domain guides.
+- `coverage-inventory.md` and this implementation manifest for final evidence.
+
+## Dependencies
+
+Tasks 00 through 18, with each work order's targeted evidence recorded.
+
+## Risks
+
+- Registry-only checks can pass while a real UI field remains absent.
+- Installed provider availability must not change the static completeness denominator.
+- Lifecycle tools keep the total MCP surface larger than five tools.
+
+## Parallelism
+
+`sequential`
+
+## Inputs
+
+- Both system designs, all requirement IDs, and the independent field inventory.
+- Prior work-order results, MCP profile assembly tests, public-docs coverage conventions, and `.github/AGENTS.md` before CI edits.
+
+## Results
+
+Completed on 2026-09-09.
+
+- Added the independent inventory delivery gate and backend registry completeness test.
+- Added deterministic generated snapshots, CI freshness checks, public coverage evidence, and docs.
+- Added real MCP desktop and mobile scenarios covering search, description, read, update, and resource lookup.
+- Focused implementation gates passed; the full backend-suite caveat is recorded in the parent plan.
diff --git a/docs/public/agents-and-profiles.md b/docs/public/agents-and-profiles.md
index 0911b29b38..bcfa608a5d 100644
--- a/docs/public/agents-and-profiles.md
+++ b/docs/public/agents-and-profiles.md
@@ -171,6 +171,14 @@ Select an agent, create a profile, then open **Settings > Agents > _Agent_ > _Pr
| Auto-approve all permissions | Answers automatically: the first `allow_once`/`allow_always` option, otherwise the first option supplied by the agent; no options cancels. It is off by default. |
| MCP servers | Adds profile-specific external MCP servers when the agent supports MCP. |
+Agents can inspect and update declared profile settings through the compact
+`search_settings_kandev`, `describe_setting_kandev`, `get_settings_kandev`,
+and `update_settings_kandev` tools. Use the separate
+`agent_profile_mcp` target for the profile MCP document. The settings tools
+preserve profile validation and save replacement lists atomically. They never
+return environment values or MCP credentials; use references or the existing
+interactive credential flow when a secret is required.
+
Model, mode, command, and configuration choices are probed from the locally installed CLI and cached. The managed **Update agent** action refreshes them automatically; after other CLI changes, refresh the profile manually. Probe status can report **auth required**, **not installed**, **not configured**, or **failed**; a saved model name does not prove that the current provider account can use it.
Configuration options are resolved for the model selected in the profile. An
diff --git a/docs/public/automation-and-mcp.md b/docs/public/automation-and-mcp.md
index 245e9c0ecc..218f2379d0 100644
--- a/docs/public/automation-and-mcp.md
+++ b/docs/public/automation-and-mcp.md
@@ -734,14 +734,46 @@ Kandev does not upgrade or proxy configured third-party MCP servers. Their suppo
This compatibility work does not add MCP Tasks, new OAuth behavior, or third-party MCP proxying.
-External MCP exposes 42 tools in these groups:
+External MCP exposes tools in these groups:
- workspace/workflow configuration: list workspaces, workflows, repositories, and workflow steps; create, update, delete, import, or export workflows; create, update, delete, or reorder steps;
- agents and profiles: list/update agents; create/delete profiles; list/update profiles; get/update profile MCP configuration;
- executors: list executors and profiles; create, update, or delete executor profiles;
- saved prompts: list prompt summaries without content or read one prompt by its exact, case-sensitive name; saved prompt tools are read-only;
+- agent-accessible settings: search setting definitions, describe a field, list authorized resource targets, read saved values, and update declared values through one compact contract;
- tasks: list, create, move, delete, archive, or update task state; list a task's sessions; read task conversation; discover or answer pending clarification questions; and discover or resolve live agent permission requests.
+### Agent-accessible settings
+
+External and task-scoped agents can use the same compact settings tools:
+
+```text
+search_settings_kandev
+describe_setting_kandev
+list_settings_resources_kandev
+get_settings_kandev
+update_settings_kandev
+```
+
+Search returns metadata only. Use `describe_setting_kandev` for the schema,
+target rules, authority, replacement behavior, and recovery guidance for one
+field. Use `list_settings_resources_kandev` when a field needs an exact
+workspace, repository, profile, task, or integration target. Then pass one
+target and the declared field paths to `get_settings_kandev` or
+`update_settings_kandev`.
+
+The backend validates every target and change against the owning domain. Writes
+keep the existing domain authorization, reference checks, atomicity, events,
+and cache behavior. Saved credential values are not returned. Secret-bearing
+fields return redacted values or safe references, and credential enrollment,
+deployment-owned configuration, plugin-owned settings, client-local state,
+and lifecycle actions remain on their existing explicit surfaces.
+
+The compact envelope is stable as domains grow. Agents should discover fields
+at runtime instead of assuming that a domain's full schema is present in the
+tool definition. Existing lifecycle tools and compatibility MCP tools remain
+available where documented.
+
`export_workflow_kandev` takes `workflow_id` and returns one version 1 `kandev_workflow` JSON document. It omits instance IDs and timestamps. Pass its JSON text unchanged as `document` to `import_workflow_kandev` when it is within the existing 1 MiB import limit.
### Read a saved prompt
diff --git a/docs/public/coverage.json b/docs/public/coverage.json
index 1f61567772..bd6b2bdf73 100644
--- a/docs/public/coverage.json
+++ b/docs/public/coverage.json
@@ -341,12 +341,20 @@
],
"sources": [
"apps/backend/internal/profiles/profiles.go",
+ "apps/backend/internal/backendapp/settings_operations.go",
+ "apps/backend/internal/settingscatalog/catalog.go",
+ "apps/backend/internal/mcp/handlers/settings_handlers.go",
+ "apps/backend/internal/mcp/server/settings_tools.go",
"apps/web/app/settings/agents/page.tsx",
"apps/web/hooks/domains/settings/use-dynamic-models.ts"
],
"tests": [
"apps/backend/internal/profiles/profiles_test.go",
+ "apps/backend/internal/backendapp/settings_operations_test.go",
+ "apps/backend/internal/mcp/handlers/settings_handlers_test.go",
+ "apps/backend/internal/mcp/server/settings_tools_test.go",
"apps/web/components/settings/agent-profile-page.test.tsx",
+ "apps/web/lib/settings-discovery/coverage-inventory.test.ts",
"apps/web/hooks/domains/settings/use-dynamic-models.test.ts"
],
"settingsRoutes": [
@@ -361,7 +369,12 @@
"list_agent_profiles_kandev",
"list_agents_kandev",
"update_agent_kandev",
- "update_agent_profile_kandev"
+ "update_agent_profile_kandev",
+ "search_settings_kandev",
+ "describe_setting_kandev",
+ "get_settings_kandev",
+ "update_settings_kandev",
+ "list_settings_resources_kandev"
]
},
{
diff --git a/docs/public/websocket-api.md b/docs/public/websocket-api.md
index bba57d9978..3b33d49aaa 100644
--- a/docs/public/websocket-api.md
+++ b/docs/public/websocket-api.md
@@ -686,6 +686,7 @@ workflow.step.updated
workflow.step.deleted
agent.profile.created
agent.profile.updated
+agent.profile.mcp_config.updated
agent.profile.deleted
task.created
task.updated
diff --git a/docs/specs/agents/README.md b/docs/specs/agents/README.md
index ac662b2a7b..a6b584bf6d 100644
--- a/docs/specs/agents/README.md
+++ b/docs/specs/agents/README.md
@@ -106,6 +106,9 @@ canonical requirement and system-design documents above.
## Related systems
+- [Settings parity](../platform/requirements/agent-settings-parity.md): owns the
+ shared discovery and interface contract. Agents retain profile data ownership.
+
- [Tasks](../tasks/README.md): consumes agent profiles for task execution.
- [Office](../office/README.md): consumes agent identities for autonomous work.
- [Platform](../platform/README.md): owns shared process and runtime services.
diff --git a/docs/specs/platform/README.md b/docs/specs/platform/README.md
index 6d6d9049e5..a3ea2c7b25 100644
--- a/docs/specs/platform/README.md
+++ b/docs/specs/platform/README.md
@@ -21,6 +21,9 @@ This system owns startup and shutdown contracts, process and port-independent
runtime safety, configuration precedence, diagnostics, notifications,
localization, feature toggles, health, and shared session recovery services.
+Settings discovery and interface parity belong to Platform. Each settings domain
+retains ownership of its values, validation, authority, and persistence.
+
## Exclusions
- Executor-specific runtime environments belong to the [executor
@@ -32,6 +35,8 @@ localization, feature toggles, health, and shared session recovery services.
### Requirements
+- [Agent-accessible Kandev settings](requirements/agent-settings-parity.md)
+
- [Agent process exit and stderr drain](requirements/agent-process-exit-drain.md)
@@ -75,6 +80,9 @@ localization, feature toggles, health, and shared session recovery services.
### System design
+- [Agent-accessible Kandev settings](system-design/agent-settings-parity.md)
+- [Core settings domain adoption](system-design/agent-settings-domains.md)
+
- [Agent process exit and stderr drain](system-design/agent-process-exit-drain.md)
diff --git a/docs/specs/platform/requirements/agent-settings-parity.md b/docs/specs/platform/requirements/agent-settings-parity.md
new file mode 100644
index 0000000000..72ccf2d5cd
--- /dev/null
+++ b/docs/specs/platform/requirements/agent-settings-parity.md
@@ -0,0 +1,168 @@
+---
+status: draft
+system: platform
+created: 2026-09-08
+owners:
+ - kandev
+---
+
+# Agent-accessible Kandev settings requirements
+
+## Overview
+
+The configuration assistant must find and change supported settings with the same authority and results as the user interface.
+Platform owns this contract across settings domains. Each domain retains ownership of its data, permissions, validation, and execution behavior.
+
+This delivery covers the core settings domains in requirement 006, not only agent profiles.
+Agents can configure existing resources and use explicit lifecycle operations for supported setup tasks.
+Every built-in Settings control receives a coverage classification. Discovery explains exceptions instead of hiding unsupported controls.
+The existing document path and requirement IDs remain stable after this scope expansion.
+
+## Terminology
+
+- **Setting:** A named value within an existing resource.
+- **Scope:** The resource and authority that determine a setting's meaning.
+- **Support status:** Supported, read-only, interactive-only, client-local, or not-yet-supported, with a reason for each limitation.
+- **Saved value:** The value stored for future use. It does not describe an active session's effective state.
+
+## Requirements
+
+### REQ-PLATFORM-AGENT-SETTINGS-PARITY-001: Discoverable coverage
+
+**Intent:** The assistant can identify supported settings and explain limitations before it attempts a change.
+
+#### Acceptance criteria
+
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-001.1:** Search shall match setting names, stable keys, descriptions, and curated aliases. Search shall not inspect saved values or secrets.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-001.2:** Each result shall identify its resource scope, support status, and Settings destination. Each limitation shall include a reason.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-001.3:** Detailed discovery shall provide types, allowed values, defaults or inheritance rules, change timing, required authority, and available operations.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-001.4:** Discovery shall report its covered domains. An unknown setting shall produce an explicit not-found result without a guessed operation.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-001.5:** Every built-in Settings control and editable domain field shall have an operation or explicit limitation. Nested fields and separate documents shall participate.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-001.6:** Search results shall name the setting, owning resource, mutation field, support status, and match reason without returning full resource schemas.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-001.7:** Detailed discovery shall identify dependent fields, replacement behavior, and required references. Resource context shall determine applicable choices.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-001.8:** Ambiguous search shall retain distinct results with their scopes. Search shall never select a resource or perform a mutation.
+
+### REQ-PLATFORM-AGENT-SETTINGS-PARITY-002: Equivalent profile changes
+
+**Intent:** A supported profile change has the same meaning through the assistant and the user interface.
+
+#### Acceptance criteria
+
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-002.1:** Profile creation and updates shall accept the same supported fields, defaults, normalization, and domain validation as the user interface.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-002.2:** An omitted update field shall remain unchanged. Explicit false, empty strings, empty maps, and empty lists shall retain their documented meanings.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-002.3:** The assistant shall discover valid model-dependent choices for a selected profile context. Unavailable discovery shall report its state without inventing choices.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-002.4:** Rejected changes shall preserve saved state. Dependency conflicts and dynamic-profile version conflicts shall identify the same recovery choices as the user interface.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-002.5:** Each successful mutation shall publish one equivalent profile notification. Existing tool names and valid argument meanings shall remain compatible.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-002.6:** Saved-value reads shall identify the target profile and distinguish stored values from unresolved defaults and active-session state.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-002.7:** The configuration assistant shall use a compact update operation for adopted settings. New fields shall not enlarge its advertised argument schema.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-002.8:** The backend shall validate each update against the current registered resource contract before applying any change.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-002.9:** Invalid updates shall return structured field errors and a discovery reference. Unknown fields shall not be ignored or corrected automatically.
+
+### REQ-PLATFORM-AGENT-SETTINGS-PARITY-003: Authority and sensitive values
+
+**Intent:** Discovery and broader field coverage do not grant additional authority.
+
+#### Acceptance criteria
+
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-003.1:** Each mutation shall enforce its existing user, workspace, resource, or organization authority at invocation. Discovery alone shall not authorize a mutation.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-003.2:** Missing or invalid identity shall not grant write access under enforced authentication. Auth-disabled installations shall preserve their existing single-user behavior.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-003.3:** New discovery and saved-value tools shall not reveal credential contents. They shall report redaction explicitly and preserve secret references as references.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-003.4:** A dependency override shall require the existing explicit confirmation flow. The assistant shall not automatically retry a conflict with an override.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-003.5:** Ordinary task, Office, and automation tool profiles shall not gain settings mutation authority from the catalog.
+
+### REQ-PLATFORM-AGENT-SETTINGS-PARITY-004: Visible results and draft preservation
+
+**Intent:** Users can observe assistant changes without losing unfinished edits.
+
+#### Acceptance criteria
+
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-004.1:** An open, clean editor for an adopted setting shall show an accepted assistant change without reload. The same value shall remain after reload.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-004.2:** An external change shall not erase a dirty draft. The editor shall explain the conflict and require a fresh baseline before another save.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-004.3:** An acknowledgement of the editor's own save shall not create a false conflict or erase newer edits.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-004.4:** Desktop and phone shall provide the same result and recovery through existing settings routes and shared save controls.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-004.5:** New visible messages shall use the selected language. Keyboard and touch users shall reach the recovery action without horizontal page scrolling.
+
+### REQ-PLATFORM-AGENT-SETTINGS-PARITY-005: Coverage regression detection
+
+**Intent:** New fields and domains cannot silently recreate the settings coverage gap.
+
+#### Acceptance criteria
+
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-005.1:** The coverage check shall fail for an editable adopted field or Settings control without an operation mapping or documented exclusion.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-005.2:** The checks shall detect schema, forwarding, persistence, error, and notification differences between supported interfaces.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-005.3:** Removing a catalog entry or adding an uncataloged field to an independent domain contract shall make the coverage check fail.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-005.4:** CI shall run registry completeness, generated-contract freshness, and search-quality checks for relevant changes.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-005.5:** A new adopted setting shall not add a tool or embed its schema in the compact tools' advertised definitions.
+
+### REQ-PLATFORM-AGENT-SETTINGS-PARITY-006: Core settings coverage
+
+**Intent:** Agents can configure the main Kandev settings domains without manual UI field entry.
+
+#### Acceptance criteria
+
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-006.1:** Agents shall read and update portable user preferences, including task behavior, keybindings, appearance, terminal preferences, saved views, and utility defaults.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-006.2:** Agents shall read and update workflow settings and step settings, including prompts, profile bindings, events, and admission policies.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-006.3:** Agents shall read and update workspace defaults, repository settings, repository scripts, and repository-set settings.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-006.4:** Agents shall read and update agent definitions, executor settings, executor profiles, and environment definitions within existing editable contracts.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-006.5:** Agents shall read and update task configuration fields without bypassing active-session restrictions or triggering a lifecycle transition through a settings patch.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-006.6:** Agents shall read and update saved prompts, utility agents, and editor definitions. Built-in resource restrictions shall remain effective.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-006.7:** Agents shall read and update notification-provider settings and event subscriptions without disclosing saved credentials.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-006.8:** Agents shall update noncredential settings, presets, and watch configuration for built-in GitHub, GitLab, Azure DevOps, Jira, Linear, and Sentry integrations.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-006.9:** Agents shall read and update existing workspace automations and their triggers. Enabled-state changes shall report their scheduling effects.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-006.10:** Authorized agents shall update permitted runtime overrides and storage-maintenance policies. Environment locks, restart requirements, and destructive acknowledgements shall remain effective.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-006.11:** Delivery shall cover every eligible field in these domains. A not-yet-supported classification shall not satisfy an eligible field's delivery requirement.
+
+### REQ-PLATFORM-AGENT-SETTINGS-PARITY-007: Explicit resource selection
+
+**Intent:** An agent can find the correct target without guessing identifiers or changing another user's settings.
+
+#### Acceptance criteria
+
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-007.1:** Resource lookup shall return bounded, paginated, authorized targets with names, resource types, and ownership context.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-007.2:** Personal settings shall resolve to the authenticated caller. Workspace-scoped settings shall require an explicit workspace or an authorized resource that determines it.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-007.3:** Contradictory selectors shall fail before mutation. Foreign resources shall not reveal their existence through lookup or detailed discovery.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-007.4:** Lookup shall preserve ambiguous candidates. Settings search shall find definitions rather than search saved values or select a target.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-007.5:** Required related-resource choices shall use authorized lookup. A returned choice shall not bypass validation during a later update.
+
+### REQ-PLATFORM-AGENT-SETTINGS-PARITY-008: Domain invariants
+
+**Intent:** Compact tools preserve domain rules for combined values, dependencies, and persistence.
+
+#### Acceptance criteria
+
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-008.1:** Each update shall validate the resulting resource, including unchanged values and related-resource constraints, before committing the change.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-008.2:** Rejected updates shall not partially persist a settings patch. Required domain atomicity shall apply across every supported write interface.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-008.3:** Concurrent updates shall retain existing version checks and domain invariants. The assistant shall not report a settings revision as a concurrency guarantee without enforcement.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-008.4:** Successful updates shall preserve domain notifications, cache invalidation, and scheduling effects. Results shall distinguish saved state from active runtime state.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-008.5:** Maps, arrays, clearing, and nullable fields shall have discoverable update semantics. Redaction markers shall never overwrite saved values.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-008.6:** Missing providers and disabled features shall return explicit capability states. Their absence shall not remove static settings descriptions.
+
+### REQ-PLATFORM-AGENT-SETTINGS-PARITY-009: Explicit boundaries
+
+**Intent:** Agents can explain what requires a separate operation, user interaction, or deployment change.
+
+#### Acceptance criteria
+
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-009.1:** Client-local preferences, startup-only values, secret contents, and plugin-owned settings shall have explicit limitations and recovery instructions.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-009.2:** Settings updates shall not install software, authenticate accounts, restart Kandev, restore backups, or execute immediate cleanup operations.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-009.3:** Create, delete, import, and reorder operations shall remain explicit. Existing valid lifecycle calls shall remain compatible.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-009.4:** Descriptions shall identify lifecycle tools needed for supported setup. New editable fields shall not enlarge their advertised settings payload definitions.
+- **AC-PLATFORM-AGENT-SETTINGS-PARITY-009.5:** Agents shall not change authentication enablement, account authority, personal tokens, or their own MCP permissions through the generic settings tools.
+
+## Out of scope
+
+- Settings-file import, export, synchronization, or a new persistence source.
+- New persistence for client-local preferences, deployment environment changes, and arbitrary startup-file writes.
+- Plugin-authored settings, Office's separate organization-management model, and new runtime feature flags.
+- Credential enrollment, account authority, authentication-mode changes, and secret-value retrieval.
+- An unrestricted mutation tool, transactional multi-resource saves, or agent runtime behavior changes.
+- Agent installation, login, duplication, and deletion parity beyond existing operations.
+- Optimistic locking for all concrete-profile writes. Existing server concurrency semantics remain in force.
+
+## Related contracts
+
+- [Agent system](../../agents/README.md)
+- [Dynamic provider choices](../../agents/requirements/dynamic-provider-options.md)
+- [Settings navigation discovery](../../ui/requirements/settings-discovery.md)
+- [System design](../system-design/agent-settings-parity.md)
+- [Domain adoption design](../system-design/agent-settings-domains.md)
diff --git a/docs/specs/platform/system-design/agent-settings-domains.md b/docs/specs/platform/system-design/agent-settings-domains.md
new file mode 100644
index 0000000000..47b1c1d1d0
--- /dev/null
+++ b/docs/specs/platform/system-design/agent-settings-domains.md
@@ -0,0 +1,220 @@
+---
+status: draft
+system: platform
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-006
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+---
+
+# Core domain adoption for agent-accessible settings
+
+## Purpose and boundaries
+
+Platform owns settings access across interfaces, not the underlying domain models.
+This design extends the [shared tool contract](agent-settings-parity.md) to the main Kandev settings domains.
+Agent profiles are the first vertical slice, not the final scope.
+The package does not require a new settings file or central persistence store.
+
+## Requirement mapping
+
+| Requirement | Sections |
+| --- | --- |
+| `REQ-PLATFORM-AGENT-SETTINGS-PARITY-006` | Required domains, Completion boundary |
+| `REQ-PLATFORM-AGENT-SETTINGS-PARITY-007` | Domain adapters, Authorized targets |
+| `REQ-PLATFORM-AGENT-SETTINGS-PARITY-008` | Mutation semantics, Relationships, Visible results |
+| `REQ-PLATFORM-AGENT-SETTINGS-PARITY-009` | Explicit exceptions, Lifecycle operations |
+
+## Required domains
+
+Backend paths below are relative to `apps/backend/`. Resource type names are proposed stable identities.
+The table defines domain boundaries, not another runtime field allowlist.
+
+| Domain and resource types | Source contracts and services | Required coverage |
+| --- | --- | --- |
+| Profiles: `agent_profile`, `agent_profile_mcp` | `internal/agent/settings/dto/`, `controller/`, `handlers/` | Concrete and dynamic profiles, launch fields, model choices, separate MCP document |
+| Agent definitions: `agent` | `internal/agent/settings/handlers/handlers.go`, `controller/` | Editable name, enabled state, and custom-agent definition fields. Computed capabilities remain read-only. |
+| Personal: `user_settings` | `internal/user/dto/dto.go`, `controller/`, `service/` | Portable task behavior, keybindings, terminal preferences, appearance, views, presets, utility defaults, and LSP preferences |
+| Workflows: `workflow`, `workflow_step` | `internal/task/dto/requests.go`, `internal/workflow/controller/controller.go`, `service/` | Workflow names and prompts, step bindings, events, session policies, admission limits, and editable ordering settings |
+| Workspace: `workspace`, `repository`, `repository_script`, `repository_set` | `internal/task/dto/requests.go`, `handlers/`, `service/` | Workspace defaults, repository identity fields permitted by the UI, branch policies, scripts, copy rules, and repository sets |
+| Execution: `executor`, `executor_profile`, `environment` | `internal/task/dto/requests.go`, `internal/task/handlers/`, `service/`, `internal/agent/executor/` | Current executor types, profile preparation settings, supported connection fields, secret references, and environment definitions |
+| Task: `task` | `internal/task/dto/requests.go`, `internal/task/service/`, `internal/mcp/handlers/` | Editable task metadata and permitted launch defaults. Session actions and workflow movement remain lifecycle operations. |
+| Prompts: `prompt` | `internal/prompts/dto/dto.go`, `controller/`, `service/` | Saved name and content with existing built-in restrictions |
+| Utilities: `utility_agent` | `internal/utility/dto/dto.go`, `controller/`, `service/`, `profilebinding/` | Prompt, name, enabled state, and canonical profile binding. Legacy migration fields do not become new controls. |
+| Editors: `editor` | `internal/editors/dto/dto.go`, `controller/`, `service/` | Saved editor definitions and kind-specific settings. Installation detection remains read-only. |
+| Notifications: `notification_provider` | `internal/notifications/dto/dto.go`, `controller/`, `service/` | Provider name, enabled state, event subscriptions, and validated provider settings |
+| Issue integrations: `jira_settings`, `linear_settings`, `sentry_instance`, and their watch types | `internal/jira/`, `internal/linear/`, `internal/sentry/` | Noncredential defaults, filters, existing instance settings, watch bindings, and watch schedules |
+| Code-host integrations: `github_settings`, `gitlab_settings`, `azure_devops_settings`, and their watch/preset types | `internal/github/`, `internal/gitlab/`, `internal/azuredevops/` | Repository scope, defaults, action/query presets, and issue/review watch settings |
+| Automations: `automation`, `automation_trigger` | `internal/automation/models.go`, `service.go`, `handlers.go` | Existing workspace automation definitions, continuation policies, bindings, and trigger schedules |
+| Runtime: `runtime_flag` | `internal/runtimeflags/registry.go`, `service.go`, `handlers.go` | Existing mutable overrides except authentication enablement. Reads include source, lock, and pending-restart state. |
+| Storage: `storage_maintenance` | `internal/system/storage/settings.go`, `handler.go`, policy types | Schedule and retention policies through the current settings operation, without running cleanup |
+
+Task behavior preferences belong to `user_settings`, not the current task.
+Portable colors and task-view preferences remain personal even when their values contain task IDs.
+Workspace integration settings do not become personal preferences because a browser owns the current workspace selection.
+Sentry uses instance identity plus workspace identity. It must not collapse into a workspace singleton.
+
+## Domain adapters
+
+Each owner contributes metadata, typed request schemas, target rules, read projections, resource lookup, and mutation adapters.
+Adapters use the shared catalog interfaces. Backend composition injects existing controllers and services.
+The shared catalog never imports every domain or dispatches arbitrary HTTP routes supplied by callers.
+
+Schema extraction follows the actual wire contract, not an untagged internal struct's Go field names.
+Several task DTOs lack JSON tags. Their current HTTP request bodies need shared, tagged domain contracts before schema generation.
+Existing camelCase integration keys remain camelCase where that is their public contract.
+Canonical catalog keys remain stable, with `field_path` identifying the actual wire field.
+
+Opaque JSON fields need domain-specific schemas or a documented typed-map boundary.
+An `interface{}` or `json.RawMessage` alone is not evidence that arbitrary nested writes are safe.
+Computed fields, compatibility inputs, workflow state, credential contents, and operational history receive explicit classifications.
+
+One composition registry serves the exporter and production registration through the same metadata constructors.
+The exporter has no credentials, live database, provider probes, or runtime services.
+Its all-domain snapshot is `apps/web/lib/settings-discovery/contract.generated.json`.
+The profile-only snapshot remains a derived subset for the existing profile work orders.
+
+## Authorized targets
+
+The shared target and lookup rules are defined in the main design.
+Personal adapters call `user.Controller.GetUserSettings` and `UpdateUserSettings` with trusted context, without an arbitrary user ID.
+Workspace resources use existing task-service authorization. Workflow steps use the workflow controller's scoped entry points.
+Install-owned writes enforce the exact existing permission, not a universal catalog permission.
+For example, profile mutation uses `org.config.manage`, while runtime overrides use `org.settings.manage`.
+
+Static metadata is available without reading a saved resource.
+Detailed values, resource names, references, and contextual choices require the same visibility checks as their domain UI.
+Adapters reject missing identity when authentication is enforced, including services that otherwise interpret missing identity as an internal caller.
+No generic endpoint permits a caller to set identity, ownership, tool profile, or authorization mode.
+
+## Mutation semantics
+
+Each update represents one domain operation. It preserves omission, explicit empties, nullability, defaults, and current replacement rules.
+Maps and arrays are not universally deep-merged. Descriptions state their exact semantics.
+Related fields can travel together in one patch, such as a utility profile binding and its supported policy fields.
+
+Existing full-document operations require one of two explicit adapters:
+
+1. A complete, validated document field with replacement semantics.
+2. A domain-owned atomic patch shared by every writer.
+
+An MCP handler must not reconstruct a full document from a redacted read.
+Integration updates preserve omitted credentials through the existing domain secret-preservation path.
+Changes to connection identity that reuse stored credentials retain the provider's existing reauthorization requirements.
+Credential enrollment and authentication-method changes remain interactive-only in this delivery.
+
+Runtime flags expose one resource per flag key. `changes.override` accepts a boolean or null to clear the stored override.
+`Service.SetOverride` retains environment locking, registry mutability, and restart behavior.
+The adapter adds the same organization-scope check as HTTP before calling that service.
+The `features.auth` descriptor is discoverable but interactive-only for writes.
+No shipped profile defaults, retired identities, or feature gate behavior change in this package.
+
+Storage policies use a complete `changes.settings` document because the current route accepts a complete policy.
+The adapter calls the same settings operation and `OnSettingsChanged` callback as the HTTP route.
+The current dedicated-Docker acknowledgement remains an exact token in domain-validated `options.confirmations`.
+Go-cache path adoption remains a separate action. A generic patch cannot set the private adoption permission.
+
+Saving an enabled watch, automation, or maintenance schedule can affect future background work.
+Descriptions explain that consequence. The domain's existing enablement, confirmation, and validation rules remain mandatory.
+Saving does not imply an immediate run or create a new scheduler.
+
+## Relationships
+
+Each adapter validates references through the owning service, not through catalog metadata alone.
+
+| Invariant | Required evidence |
+| --- | --- |
+| Workflow step references a usable profile | Missing, inaccessible, incompatible, disabled, and valid profile cases |
+| Step event references another step | Same-workflow validation and rejection of a foreign step |
+| Workspace default references an executor/profile | Authorized, compatible target and documented clearing behavior |
+| Repository copy rule stays contained | Existing copyfiles validation rejects traversal and malformed specifications |
+| Utility agent keeps a valid profile binding | Dependency conflicts, built-in restrictions, and legacy migration inputs |
+| Watch references match its workspace | Wrong-workspace workflow, profile, repository, and instance cases |
+| Task configuration respects running sessions | No hidden move, start, reassignment, or runtime rewrite |
+| Runtime override respects deployment policy | Environment lock, unknown/retired key, null reset, and pending restart |
+| Storage policy preserves adoption safety | No unconfirmed dedicated daemon or private Go-cache adoption |
+
+When a valid mutation updates several rows, the existing domain transaction remains the atomicity boundary.
+New partial-update paths need equivalent protection across all writers, not only MCP callers.
+Tests exercise competing writes for any added read-modify-write path and verify rollback after an injected persistence failure.
+This package does not add universal optimistic locking. Existing dynamic versions and domain concurrency checks remain intact.
+
+## Visible results
+
+Every domain work order includes its existing store subscription and editor reconciliation.
+The profile implementation establishes clean, dirty, submitted, and conflicted states through the existing save coordinator.
+Other editors reuse that behavior where applicable, without moving domain state into the coordinator.
+
+Existing events remain authoritative. Adapters must not duplicate event publication.
+When no suitable event exists, the domain adds a value-free invalidation after persistence.
+Invalidations route to the owning user or workspace, or authorized install-setting readers. They never broadcast private values globally.
+Refetches use target identity and request-generation guards. An invalidation during a pending read requires a fresh read.
+Delivery order without a domain revision is not proof that one snapshot is newer.
+
+Personal settings reuse `apps/web/lib/user-settings-sync.ts` and the shared wire mapper.
+Workflow drafts reuse `use-workflow-draft-contributor.ts` and `workflow-dirty-state.ts`.
+Executor profiles reuse the contributors under `components/settings/profile-edit/`.
+New invalidation handlers feed these existing paths instead of updating only the page that initiated the change.
+
+Phone and desktop keep their current settings routes, content scroll owner, and shared save controls.
+Conflict recovery stays inline and uses the current discard action. No new overlay or navigation model is required.
+Existing mobile profile, executor, notification, prompt, and utility settings tests provide the nearest shipped examples.
+New copy uses all five locales. New recovery actions preserve touch targets, keyboard access, and safe-area clearance.
+Each domain's browser scenario invokes real MCP, observes the UI, then verifies persistence after reload.
+
+## Explicit exceptions
+
+Every exception has a stable identity, owner, category, reason, and available recovery destination.
+
+| Category | Included examples | Discovery behavior |
+| --- | --- | --- |
+| `client-local` | Settings-menu shape, chart-motion preference, pane sizes, collapsed navigation | Explain the device boundary and link to the control. No remote browser bridge. |
+| `read-only` | Installation detection, runtime health, computed capabilities, active execution snapshots | Return authorized nonsensitive state only. Never promote computed response fields into updates. |
+| `interactive-only` | Login, token enrollment, account authority, authentication enablement, credential-bearing connection identity changes | Explain the required user flow without reading credentials. |
+| `action` | Install, restart, restore, immediate cleanup, resource creation/deletion, workflow reordering | Identify an existing explicit tool or the UI action. Never encode the action as an arbitrary setting. |
+| `deployment-owned` | Startup YAML/environment, database location, launcher binaries, server ports | Derive safe metadata from `internal/common/config/catalog.go` and source provenance. No file or environment writes. |
+| `plugin-owned` | Plugin-specific settings schemas and storage | Identify the plugin settings destination. No arbitrary plugin storage mutation or new plugin API. |
+| `separate-product-contract` | Office organization, projects, channels, and autonomous workforce management | Identify Office's existing tools or UI. Workspace automations remain in scope. |
+
+Host-owned keyboard overrides include the typed plugin-shortcut override map where it already belongs to user settings.
+That does not expose arbitrary plugin-owned settings or infer action availability when the plugin is absent.
+Transient form drafts, navigation history, setup progress, and internal migration fields are not user configuration controls.
+
+New value reads redact declared credential paths. Search and resource lookup never inspect arbitrary saved values.
+Free-form prompt and script bodies are returned only by explicit authorized value reads, not search snippets or logs.
+The catalog does not claim that it can detect every secret a user writes into free-form text.
+Legacy external raw-MCP-document reads retain their current exposure contract.
+
+## Lifecycle operations
+
+Four settings tools plus one generic resource lookup form the shared settings interface.
+They do not replace explicit lifecycle tools or turn updates into silent upserts.
+Existing create/delete/import/reorder tools remain available through their current domain owners.
+New fields on adopted create tools use a validated `settings` object, with duplicate legacy arguments rejected.
+
+For prompt, utility-agent, editor, and notification-provider setup, domain work orders add explicit create adapters where no MCP create tool exists.
+These tools use parent selectors where required and one validated settings object.
+The catalog describes their complete create schema on demand. The outer tool definitions do not grow with new fields.
+Creation preserves built-in restrictions and does not install, authenticate, execute, or test external credentials.
+Other new lifecycle families, including provider account enrollment and resource destruction, remain outside this package.
+
+## Completion boundary
+
+The inventory covers Settings routes, navigation definitions, independent UI payload types, backend mutation bodies, and persisted response fields.
+Navigation entries alone cannot prove completeness because some entries represent sections instead of individual fields.
+The first work order produces a checked inventory from these inputs, including missing navigation controls and explicit exception records.
+
+CI compares independent inputs against the catalog and the inventory. It must detect a new route, domain, nested typed field, or editable control.
+Negative fixtures add each kind of omission and remove a descriptor. Every fixture must fail the appropriate coverage assertion.
+Dynamic maps count as typed contracts, not as one new setting per saved key or provider option.
+The completion report separates supported fields, read-only fields, exceptions, and pending work by domain.
+Every eligible field in the required domains must be supported. Pending work cannot be relabeled as an exception to pass delivery checks.
+The report does not claim a coverage percentage until the independent inventory establishes its denominator.
+
+## Related decisions
+
+- [Domain-owned settings catalog](../../../decisions/2026-09-08-domain-owned-settings-catalog.md)
+- [Portable personal settings](../../../decisions/0041-backend-owned-portable-user-settings.md)
+- [Runtime overrides](../../../decisions/0018-runtime-settings-overrides.md)
+- [Workspace integration settings](../../../decisions/0030-workspace-scoped-integration-settings.md)
diff --git a/docs/specs/platform/system-design/agent-settings-parity.md b/docs/specs/platform/system-design/agent-settings-parity.md
new file mode 100644
index 0000000000..4b281da712
--- /dev/null
+++ b/docs/specs/platform/system-design/agent-settings-parity.md
@@ -0,0 +1,425 @@
+---
+status: draft
+system: platform
+requirements:
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-001
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-002
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-003
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-004
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-005
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-007
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-008
+ - REQ-PLATFORM-AGENT-SETTINGS-PARITY-009
+---
+
+# Agent-accessible Kandev settings system design
+
+## Purpose and boundaries
+
+Platform owns the shared discovery contract across settings domains.
+Each domain remains the source of truth for its values and operations.
+Profiles establish the first implementation slice. They are not the delivery boundary.
+The [domain adoption design](agent-settings-domains.md) defines the required core domains and explicit exceptions for this delivery.
+
+The frontend navigation catalog remains a presentation contract.
+This design connects existing destinations to domain setting IDs without replacing navigation, ranking, translations, or focus behavior.
+
+The [ownership decision](../../../decisions/2026-09-08-domain-owned-settings-catalog.md) defines the extension boundary.
+
+## Requirement mapping
+
+| Requirement | Design sections |
+| --- | --- |
+| `REQ-PLATFORM-AGENT-SETTINGS-PARITY-001` | Catalog, Discovery tools, Coverage |
+| `REQ-PLATFORM-AGENT-SETTINGS-PARITY-002` | Shared requests, Mutation adapters, Dynamic choices |
+| `REQ-PLATFORM-AGENT-SETTINGS-PARITY-003` | Authority, Sensitive values |
+| `REQ-PLATFORM-AGENT-SETTINGS-PARITY-004` | Editor reconciliation |
+| `REQ-PLATFORM-AGENT-SETTINGS-PARITY-005` | Coverage |
+| `REQ-PLATFORM-AGENT-SETTINGS-PARITY-007` | Discovery tools, Target contract |
+| `REQ-PLATFORM-AGENT-SETTINGS-PARITY-008` | Compact update validation, Mutation adapters |
+| `REQ-PLATFORM-AGENT-SETTINGS-PARITY-009` | Lifecycle and compatibility tools, Sensitive values |
+
+## Current implementation
+
+- `internal/agent/settings/handlers/handlers.go` declares private create/update bodies and maps them to controller requests.
+- `internal/agent/settings/controller/profile_crud.go` owns defaults, normalization, dependencies, dynamic-profile versions, and persistence.
+- `internal/mcp/server/config_handlers.go` declares a smaller schema and manually forwards selected fields.
+- `internal/mcp/handlers/config_agent_handlers.go` decodes another smaller request shape.
+- The UI saves through `components/settings/agent-profile-page-state.ts` and the existing agent settings actions.
+- `internal/mcp/handlers/workflow_step_parity_test.go` compares REST and MCP notifications over a shared store.
+- `internal/common/config/catalog.go` describes startup settings. It does not own profile values.
+- `lib/settings-discovery/` describes navigation destinations. It does not own mutation schemas.
+
+All backend paths in this document are relative to `apps/backend/`.
+All frontend paths are relative to `apps/web/`.
+
+## Catalog
+
+A new `internal/settingscatalog` package owns metadata types and bounded metadata search.
+It contains no database access, credentials, global setters, or provider execution.
+The agent domain contributes entries from `internal/agent/settings/catalog`.
+Other domains contribute adjacent catalog adapters, as specified in the domain adoption design.
+Backend composition supplies registered adapters to MCP handlers. The shared package does not import domain services.
+
+Each setting descriptor contains:
+
+| Field | Meaning |
+| --- | --- |
+| `key` | Stable identity, such as `agent_profile.fallback_model` |
+| `domain` | Owning settings domain, such as `agent_profiles` or `user_preferences` |
+| `resource_type` | Registered adapter identity, such as `agent_profile`, `workflow_step`, or `user_settings` |
+| `scope` | Caller-owned, workspace-owned, or install-owned, with explicit selector rules |
+| `description`, `aliases` | Curated English metadata for agents, without saved values |
+| `label` | Short human-readable setting name for search results |
+| `schema` | Field shape derived from the shared domain request |
+| `default_behavior` | Explicit default, provider inheritance, or no default |
+| `support` | Status, reason, and optional recovery destination |
+| `classification` | Writable field, computed field, action, or reasoned exception category |
+| `operations` | Compact update binding, lifecycle operations, field paths, and replacement rules |
+| `dependencies` | Related setting keys, resource references, and required companion fields |
+| `required_scope` | Existing domain authority, including `org.config.manage` for writes |
+| `applies_when` | Metadata update, future launch, future selection, or provider-dependent behavior |
+| `sensitive_paths` | Paths that require omission or redaction in new value reads |
+| `settings_href` | Canonical settings route after resource resolution, or explicit absence |
+
+Descriptors are immutable process metadata. They do not store current values or authority decisions.
+Descriptions stay adjacent to operation bindings. No second hand-maintained type or field allowlist exists in MCP.
+Dynamic maps declare typed values rather than enumerating provider-specific keys.
+
+Search returns at most 50 entries, with a default limit of 20 and an offset cursor.
+Queries have a maximum length of 256 characters. Matching is case-insensitive token matching over metadata only.
+Search tokenization splits whitespace, dots, underscores, and hyphens.
+Exact keys and labels rank first, followed by prefixes and aliases, then descriptions. Stable keys break ties.
+Domain context can narrow results but cannot make an unrelated field match by itself.
+No fuzzy match changes a key or selects an update target.
+An empty query lists the domain's descriptors in stable order.
+This delivery does not introduce embeddings, external search, or translated backend search.
+
+A result includes `key`, `label`, `description`, `resource_type`, `field_path`, `support`, `match_reason`, and `settings_href` when resolvable.
+It names `describe_setting_kandev` as the next step. It does not embed full schemas, current values, or resource lists.
+Descriptions explain behavior and important dependencies. For example, fallback-model metadata states that automatic fallback takes precedence.
+An ambiguous query returns separately labeled candidates. Resource selection remains explicit.
+
+Registry construction rejects duplicate keys, missing owners, unresolved operation bindings, and unsupported schema shapes.
+A writable descriptor requires a registered validator, mutation adapter, and authority rule.
+Every exclusion requires a reason. Documentation-only descriptors cannot become writable by changing a status string.
+
+## Shared requests
+
+Move the HTTP create/update body definitions into exported agent-domain contracts under `internal/agent/settings/dto/`.
+Both transports decode these types and use one conversion path into controller requests.
+Transport identifiers stay outside the domain patch. Compact reads and updates use the shared `target` object.
+Existing lifecycle and compatibility tools retain their profile or agent selectors.
+Dependency confirmation remains an operation argument, not a saved setting.
+
+Generate domain validation schemas from the shared typed contracts and enrich fields with catalog descriptions.
+Use the existing JSON Schema dependencies. Compile every generated schema through `internal/mcp/toolschema.Compile`.
+Generated schemas must preserve the existing Draft 7 validation boundary.
+Compatibility adapters remain explicit and covered by tests.
+The compact tools advertise only stable envelope schemas. Full domain schemas are returned by description or used internally for validation.
+No enum of setting keys and no `oneOf` of all resource schemas appears in those envelopes.
+
+The following table is the initial field inventory. It is design evidence, not another runtime allowlist.
+
+| Fields | Operations and semantics |
+| --- | --- |
+| `name` | Create/update. Required nonblank name on creation and when supplied on update. |
+| `model`, `mode` | Create/update. Empty model retains the existing provider-default behavior. |
+| `fallback_model`, `auto_fallback` | Create/update with the existing fallback precedence. |
+| `config_options` | Create/update. Replace the supplied map, then apply current domain sanitization. |
+| `auto_approve`, `allow_indexing` | Create/update. Preserve legacy compatibility. Mark `allow_indexing` as deprecated metadata. |
+| `cli_passthrough`, `cli_flags` | Create/update with current capability rules. A supplied flags list replaces the full list. |
+| `env_vars`, `command_prefix` | Create/update through existing validators and secret-reference checks. |
+| `enabled` | Update. Creation retains the domain's existing enabled default. |
+| `dynamic` | Create/update through current candidate validation, feature availability, and version rules. |
+| `mcp.enabled`, `mcp.servers` | Compact read/update with `resource_type: agent_profile_mcp`. Separate resource operation using the profile ID. |
+
+The MCP document also carries opaque `meta`. Classify this field as preserved metadata, not an editable UI control.
+The shared document adapter preserves it when the caller omits it.
+The HTTP `mcpServers` spelling remains a compatibility alias for `servers`.
+The compact document adapter accepts canonical `servers`. Existing dedicated MCP tools remain external compatibility adapters.
+
+`id`, `agent_id`, `kind`, timestamps, billing metadata, and other computed response fields are not generic writable settings.
+Each noneditable response field has an explicit coverage classification.
+Agent-level fields such as `supports_mcp` remain outside the profile mutation contract.
+
+On update, omission leaves a value unchanged. False, zero, empty strings, empty maps, and empty lists survive transport conversion.
+Empty collections mean replacement with an empty collection where the domain supports clearing.
+There is no universal reset operation or new meaning for null.
+Existing HTTP null behavior remains compatible. Newly exposed MCP fields reject null unless their published schema explicitly permits it.
+
+## Discovery tools
+
+Register a `configuration-settings` group through the existing typed MCP profile registry.
+The configuration and external surfaces receive these tools. Ordinary task, Office, and automation surfaces do not receive this group.
+The configuration surface replaces adopted read/update tools with the compact group after equivalent coverage passes.
+The external surface retains existing tool names and successful argument forms for compatibility.
+Legacy tools remain visible until their adapters pass their work-order checks.
+Lifecycle and interaction tools remain explicit. External compatibility tools retain their existing schemas.
+
+| Proposed tool | Arguments | Result |
+| --- | --- | --- |
+| `search_settings_kandev` | `query`, optional `domain`, `limit`, `cursor` | Descriptor summaries, covered domains, and next cursor |
+| `describe_setting_kandev` | `key`, optional `target`, `context`, `operation`, `include_resource_schema` | Detailed descriptor, dependencies, optional operation schema, and current capability status |
+| `get_settings_kandev` | `target`, `keys` | Saved-value projection for up to 50 keys, with explicit redaction and source |
+| `update_settings_kandev` | `target`, `changes`, optional `options` | Accepted field names and revision metadata, or a structured tool error |
+| `list_settings_resources_kandev` | `resource_type`, optional `workspace_id`, `query`, `limit`, `cursor` | Authorized target summaries, explicit empty state, and next cursor |
+
+`describe_setting_kandev` works without a target for static schema information.
+The setting key determines the descriptor's resource type. A supplied target must match that type.
+For creation, the domain's validated `context` names required parents, such as `agent_id` for a profile.
+`operation` defaults to `update` and also accepts `create` for profile lifecycle schema discovery.
+`include_resource_schema` defaults to false. When true, the result includes the selected operation's complete domain schema and required fields.
+This supports related settings and dynamic-profile creation without loading every schema upfront.
+The agent adapter's context contains optional `agent_id`, `model`, `mode`, and `config_options` for discovery before saving.
+Other adapters define their own closed context schemas. Unknown context fields fail before domain lookup.
+Context supplies no identity, authority, executable binding, or persistence operation.
+
+`get_settings_kandev` requires one registered resource type and target. It does not infer a profile from the calling agent.
+`keys` contains canonical descriptor keys belonging to that resource type.
+Unknown domains and keys return typed errors. A domain outside coverage is not an empty successful value response.
+New reads include `source: profile`, available revision metadata, and the descriptor's change timing.
+Profile fields carry `updated_at`. The separate MCP document does not borrow that timestamp or claim an equivalent revision.
+An inherited model has an explicit inheritance marker. A saved profile read never claims to show an active session's effective model.
+The tool does not accept arbitrary paths or resolve credential contents.
+
+The configuration prompt at `config/prompts/config-context.md` introduces discovery before settings changes.
+It teaches search, resource lookup, describe, read, and update without repeating every optional field.
+The prompt states supported domains and preserves the existing destructive-action confirmation instruction.
+
+## Target contract
+
+The shared target is `{resource_type, resource_id?, workspace_id?}`. No resource-type enum appears in its advertised schema.
+The registry defines each type's required selectors. Unknown types and extra selectors fail closed.
+
+- `user_settings` accepts neither resource ID nor workspace ID. The existing user service resolves the trusted caller.
+- Workspace singleton adapters require `workspace_id` and reject a resource ID.
+- Entity adapters require `resource_id`. Their domain resolves and authorizes the containing workspace.
+- A supplied workspace ID must match the authorized entity's workspace. It never overrides ownership.
+- Install singleton adapters accept neither ID. They enforce their existing organization scope.
+- `runtime_flag` uses its registered flag key as `resource_id`, allowing one atomic override operation per request.
+
+Resource lookup is a fifth bounded discovery tool, not another settings mutation tool.
+It uses existing authorized domain list services and returns only IDs, labels, parent context, and complete targets.
+The default limit is 20, the maximum is 50, and the query limit is 256 characters.
+Query matching is limited to resource labels and public identifiers, never prompt bodies, command strings, credentials, or arbitrary saved values.
+Filtering and authorization precede pagination. Cursors bind the caller, resource type, query, and workspace scope.
+Foreign resources and missing resources produce the same not-visible result. Singleton lookup returns only the caller's permitted singleton.
+Where existing lists are unbounded, adapters add bounded service queries rather than loading the entire table for every page.
+Existing list tools remain compatibility operations. No new per-domain list tool is required.
+
+## Compact update validation
+
+The outer `update_settings_kandev` schema requires a target and nonempty object of changes.
+It allows at most 50 top-level changed fields and a 256 KiB serialized changes object.
+The root envelope is closed. The nested changes object receives domain validation at invocation.
+These limits do not replace existing stricter domain limits.
+
+The backend performs this sequence before mutation:
+
+1. Resolve the exact registered resource adapter and trusted caller context.
+2. Authorize the operation and load the selected resource through its domain service.
+3. Select the current update schema from that adapter and resource context.
+4. Validate the patch shape, then validate the resulting resource through the domain's update operation.
+5. Decode the shared typed patch and invoke the existing domain mutation once.
+6. Return accepted field names and available revision metadata without echoing sensitive values.
+
+Closed typed objects reject unknown keys. Only domain-declared maps permit arbitrary keys with the domain's value type.
+An update cannot mix profile fields with the separate MCP document, create an undeclared resource type, or write an arbitrary database column.
+The request never contains executable bindings or a caller-supplied schema.
+The optional `options` object receives a closed schema from the selected adapter.
+Profile adapters accept `force`, false by default. Other adapters reject this option unless their domain explicitly supports it.
+Storage acknowledgements retain their exact confirmation tokens. No generic force flag bypasses unrelated domain checks.
+Descriptions return option schemas on demand. Adding domain options does not enlarge the advertised outer envelope.
+
+Domain validation checks the patch together with unchanged saved values and authorized references.
+Adapters never perform an unlocked read, merge, and full replacement when that can erase unrelated concurrent changes.
+Partial updates use atomic domain patches. Required read-modify-write operations use the domain's transaction or version mechanism across REST, WS, and MCP.
+An adapter-only mutex cannot protect other writers or multiple backend processes.
+No single request spans independent resources. A domain operation can update dependent rows atomically when its invariant requires that operation.
+Validation failures produce no writes. Failed post-save probes report a saved result with degraded capability, not a false rollback claim.
+
+Validation errors contain `code`, canonical setting key, JSON field path, a safe expected-type description, and the suggested description call.
+Errors never echo submitted values. Unknown-field suggestions are advisory and are never applied automatically.
+The server validates against current rules even when the caller used an older description response.
+Capability failures retain their typed state and do not cause guesses or retries with relaxed validation.
+Static registry schema revisions are content hashes for cache invalidation, not authority tokens or resource concurrency versions.
+
+## Lifecycle and compatibility tools
+
+Creation remains explicit because dynamic profiles require related values in one valid create request.
+`create_agent_profile_kandev` keeps `agent_id`, `name`, legacy optional `model` and `auto_approve`, and adds an optional `settings` object.
+New fields go inside `settings`, without expanding the advertised outer schema.
+Model becomes optional to support the existing domain default behavior.
+The backend validates the combined create request against the shared create contract.
+A field supplied both at the top level and inside `settings` is rejected, including equal duplicate values.
+`settings` cannot override `agent_id` or another transport identifier.
+Discovery supplies the complete create schema on request, including dynamic candidates and their required policy fields.
+
+Existing external `update_agent_profile_kandev` and MCP-document tools retain their current argument shapes and meanings.
+Their adapters use the same validators and services. New fields are accessed through the compact tools rather than added to legacy schemas.
+The configuration surface omits the adopted legacy update tools to avoid duplicate ways to change the same settings.
+Profile/resource listing and explicit create/delete operations remain available.
+Profile replacement sends the existing `tools/list_changed` notification so clients refresh their advertised tools.
+
+## Dynamic choices
+
+The agent domain adapter uses `Controller.ResolveAgentModelConfig` and existing capability discovery.
+Profile context comes from the saved profile plus explicit model-context overrides.
+Create-time discovery accepts an existing agent ID before a profile exists.
+The resolver retains its current cache, timeout, and provider-neutral response.
+
+The descriptor returns the resolver's status and full applicable choice snapshot.
+`probing`, `auth_required`, `not_installed`, and failure states remain explicit.
+The assistant cannot treat a stale or unavailable snapshot as an empty valid choice set.
+Static setting discovery remains available when the provider probe fails.
+Provider-dependent values remain the domain's validation responsibility. This work does not add a second provider policy engine.
+
+## Mutation adapters
+
+Existing REST paths, compact MCP operations, and compatibility tools call the shared domain conversion and validation path.
+Successful writes use the existing controller and stores. There is no new schema migration.
+The profile MCP document retains its separate service.
+HTTP requires `enabled` and normalizes an absent servers map to an empty map.
+Existing MCP calls treat omitted fields as unchanged. Preserve these transport defaults through explicit adapters to the same document operation.
+The catalog describes that distinction. Equivalent full inputs must produce equivalent stored documents.
+Both adapters call the controller so profile existence and MCP-support checks remain consistent.
+Profile creation followed by an MCP document update remains two operations, without an atomicity claim.
+
+The REST and MCP adapters translate typed domain failures into their native error envelopes.
+MCP preserves error code and structured dependency details across both backend clients.
+`DispatcherBackendClient` currently discards those details. Extend its error representation and the streamed backend client consistently.
+Existing human-readable error text remains available to older callers.
+An unknown argument fails at the existing tool-schema boundary before dispatch.
+
+Successful profile creation and updates produce the existing domain notification exactly once.
+Keep either the existing REST broadcast or MCP event publication for its operation.
+Do not add another publication to a shared helper while retaining both callers' publication.
+Do not introduce synthetic agent responses as a source of UI truth.
+
+The current MCP-document writers publish no update notification.
+Add `agent.profile.mcp_config.updated` as an invalidation event with `profile_id` and the domain's routing scope.
+Each accepted REST or MCP document write publishes this event once after persistence.
+The event carries no document values. An authorized open editor refetches through its existing read action.
+Refetches use a request generation and profile-ID guard. An invalidation during a pending read triggers a fresh read.
+
+## Authority
+
+REST profile mutations currently use `authz.ScopeOrgConfigManage` and the interim browser interlock.
+MCP must enforce the same organization scope from trusted request context before domain mutation.
+Use `authn.IdentityFromContext` and the existing `authz` subject/scope resolver.
+The transport owns whether authentication is enforced. Missing identity cannot become unrestricted access under enforced authentication.
+The established auth-disabled path preserves single-user operation.
+
+In-session requests retain the owner identity from `internal/mcp/scope`.
+External requests retain the authenticated PAT identity.
+The browser interlock remains a browser transport guard. MCP does not fetch or reuse its token.
+Existing automation restrictions and raw-WebSocket rejection remain effective.
+The catalog cannot manufacture a scope, user identity, profile ownership, or MCP surface from request arguments.
+
+`options.force` remains false by default for dependency-sensitive profile updates.
+A conflict returns affected utility and dynamic-profile references without a write.
+The configuration assistant uses its existing question tool before a confirmed retry.
+The same operation remains unavailable when the caller lacks organization authority.
+
+## Sensitive values
+
+Search and descriptions contain schema metadata only.
+New saved-value projections redact literal environment values and credential-bearing MCP subdocuments.
+Secret IDs remain references. The adapter never calls secret resolution to satisfy discovery.
+Redacted values include an explicit marker and cannot be round-tripped as replacement values.
+The MCP-document descriptor names the compact resource binding and the external compatibility tools' current exposure limits.
+
+Existing legacy tools can expose raw profile MCP documents under their current contract.
+This delivery does not claim a product-wide secret-redaction migration.
+New discovery logs contain setting keys, resource IDs, and outcome codes, without request values or provider error payloads.
+
+## Editor reconciliation
+
+The existing `agent.profile.updated` handler updates `settingsAgents` and profile choices.
+`useAgentProfileSettings` derives the selected profile from that store.
+Extend `useProfileEditorState` to reconcile authoritative profile updates with its local draft and saved baseline.
+Apply the same contract to `dynamic-agent-profile-editor-state.ts` and `dynamic-agent-profile-editor-draft.ts`.
+Dynamic candidate edits retain the existing server version and dependency rules.
+The separate `use-profile-mcp-config.ts` hook consumes the new document invalidation and maintains its own baseline and draft.
+An MCP document conflict blocks only its contributor. The save coordinator continues to own route-level feedback.
+
+- A clean editor adopts a newer profile and remains clean.
+- A dirty editor preserves its draft and records an external-change conflict.
+- A conflicted contributor blocks Save through the existing save coordinator and shows localized recovery copy.
+- The existing discard/reset flow adopts the latest authoritative profile and clears the conflict.
+- The editor correlates its submitted snapshot with its own response and notification. Its acknowledgement is not an external conflict.
+- A late save response cannot replace a newer authoritative baseline or remove edits made after submission.
+
+Use the existing `updatedAt` ordering and profile-ID guards for delivered snapshots.
+This is client reconciliation, not a new server compare-and-swap guarantee.
+Simultaneous concrete-profile writes retain the current server behavior. Dynamic profiles retain their existing version conflict contract.
+
+Desktop and phone use the current profile route, advanced sections, and shared Save surface.
+The nearest phone exemplar is `e2e/tests/settings/mobile-agent-profile-config-selector.spec.ts` and its profile page.
+Recovery copy stays inline beside the affected editor. It needs no new modal, drawer, or navigation layer.
+The existing content scroll owner and safe-area-aware save surface remain in use.
+Any new touch action uses a 44px hit area only for coarse pointers. Fine-pointer controls retain current density.
+All new visible copy uses the five locale catalogs. Traditional Chinese values use the existing generation command.
+
+## Coverage
+
+Coverage has three independent sources for every adopted domain:
+
+1. Shared typed create/update contracts and response fields.
+2. UI payload construction, typed editable fields, and settings controls.
+3. Catalog descriptors, generated domain schemas, and advertised envelope schemas.
+
+A generated metadata snapshot supplies stable field keys and schemas to frontend tests.
+The proposed `cmd/settings-catalog` exporter supports `--check` without writes.
+Generation is deterministic. Tests fail when the checked-in snapshot differs from the domain catalog.
+The frontend mapping ties each domain patch key and settings control to a setting ID or explicit coverage classification.
+Dynamic provider keys belong to the `config_options` descriptor, not a frozen list.
+
+Go contract tests compare complete field sets, requiredness, nested shapes, and explicit exclusions.
+Mutation tests call real registered MCP tools and real REST handlers over the same domain fixture.
+They compare persisted values, defaulting, invalid inputs, dependency details, and emitted notifications.
+At least one negative fixture adds a field outside the catalog. Another removes a descriptor.
+Both fixtures must cause the coverage assertion to fail.
+
+The existing backend and frontend test workflows run the contract checks on relevant changes.
+Add the exporter freshness command to backend CI with path coverage for its frontend snapshot.
+Tests assert that removing a required check or narrowing its path coverage causes the CI wiring check to fail.
+No branch-protection or repository-setting changes are part of this package.
+
+The search suite owns a curated query set independent of descriptor aliases.
+Cases include exact keys, `backup model`, `reasoning effort`, `command prefix`, `keyboard shortcut`, `archive confirmation`, and `workflow agent`.
+Additional cases cover repository scripts, executor defaults, notification events, integration watches, runtime locks, ambiguous `permissions`, and an unrelated query.
+Cases assert the expected first result or candidate set, correct resource scope, match reason, and no saved-value search.
+The alias and ranking implementation cannot rewrite expected results automatically.
+
+An added-setting fixture verifies that compact tool names and advertised schemas remain byte-identical.
+The description result and backend validator must recognize that same new setting.
+The named create tool's envelope receives the same stability check.
+Compatibility tests cover legacy external calls without requiring legacy schemas to grow.
+
+Focused browser tests apply a real MCP mutation while the profile page is open.
+They verify the clean update, reload persistence, dirty-draft recovery, and an acknowledgement during an in-flight save.
+Fixtures cover concrete fields, dynamic candidates, and the separate MCP document.
+Desktop and mobile scenarios use disposable profiles and causal event waits.
+The browser never dispatches raw `mcp.*` WebSocket actions as a shortcut.
+
+## Persistence and rollout
+
+No new settings store, startup source, or runtime flag identity is required.
+Domain adapters reuse current persistence and feature gates. Necessary atomic patch queries do not introduce a new persistence owner.
+External compatibility tool names and successful argument shapes remain stable.
+Compact updates and discovery ship together after their work-order checks pass.
+The configuration profile switches each adopted operation to the compact group with the existing list-changed notification.
+Public docs list all delivered domains and their specific limitations.
+The package is incomplete while an eligible required domain remains not-yet-supported.
+Domain adapters do not copy startup or runtime-flag registries.
+
+## Related decisions
+
+- [Domain-owned settings catalog](../../../decisions/2026-09-08-domain-owned-settings-catalog.md)
+- [MCP argument validation](../../../decisions/2026-08-01-validate-mcp-tool-arguments.md)
+- [MCP tool profiles](../../../decisions/2026-08-08-mcp-tool-profiles.md)
+- [Utility dependency safety](../../../decisions/2026-08-08-utility-profile-dependency-safety.md)
+- [Settings save coordinator](../../../decisions/0046-settings-route-save-coordinator.md)
+- [Navigation boundaries](../../../decisions/2026-08-04-navigation-manifest-boundaries.md)
diff --git a/scripts/settings-contract-ci.test.mjs b/scripts/settings-contract-ci.test.mjs
new file mode 100644
index 0000000000..58700a4594
--- /dev/null
+++ b/scripts/settings-contract-ci.test.mjs
@@ -0,0 +1,97 @@
+import assert from "node:assert/strict";
+import { execFileSync } from "node:child_process";
+import { readFileSync } from "node:fs";
+import { resolve } from "node:path";
+import test from "node:test";
+
+const root = resolve(new URL("..", import.meta.url).pathname);
+const backend = resolve(root, "apps/backend");
+const snapshotPath = resolve(root, "apps/web/lib/settings-discovery/contract.generated.json");
+const profileSnapshotPath = resolve(
+ root,
+ "apps/web/lib/settings-discovery/profile-contract.generated.json",
+);
+
+function readJSON(path) {
+ return JSON.parse(readFileSync(path, "utf8"));
+}
+
+test("settings catalog snapshots are fresh", () => {
+ execFileSync("go", ["run", "./cmd/settings-catalog", "--check"], {
+ cwd: backend,
+ stdio: "inherit",
+ });
+});
+
+test("settings catalog has complete deterministic identities", () => {
+ const snapshot = readJSON(snapshotPath);
+ const profileSnapshot = readJSON(profileSnapshotPath);
+ assert.equal(snapshot.schema_version, "settings-catalog.v1");
+ assert.equal(snapshot.generated_by, "cmd/settings-catalog");
+ assert.equal(profileSnapshot.schema_version, "settings-catalog.v1");
+
+ const resourceTypes = new Set();
+ for (const domain of snapshot.domains) {
+ assert.ok(domain.resource_type);
+ assert.ok(!resourceTypes.has(domain.resource_type), `duplicate ${domain.resource_type}`);
+ resourceTypes.add(domain.resource_type);
+
+ const keys = new Set();
+ const paths = new Set();
+ for (const field of domain.fields) {
+ assert.ok(!keys.has(field.key), `duplicate field key ${field.key}`);
+ assert.ok(!paths.has(field.field_path), `duplicate field path ${field.field_path}`);
+ keys.add(field.key);
+ paths.add(field.field_path);
+ if (field.support === "supported" && field.writable) {
+ assert.equal(field.classification, "writable", field.key);
+ assert.ok(field.validator, field.key);
+ assert.ok(field.authority, field.key);
+ }
+ assert.notEqual(field.support, "pending", field.key);
+ }
+ }
+
+ for (const resourceType of [
+ "agent_profile",
+ "agent_profile_mcp",
+ "user_settings",
+ "workflow",
+ "workflow_step",
+ "workspace",
+ "repository",
+ "repository_script",
+ "repository_set",
+ "executor",
+ "executor_profile",
+ "environment",
+ "task",
+ "prompt",
+ "utility_agent",
+ "editor",
+ "notification_provider",
+ "automation",
+ "automation_trigger",
+ "runtime_flag",
+ "storage_maintenance",
+ ]) {
+ assert.ok(resourceTypes.has(resourceType), `missing ${resourceType}`);
+ }
+});
+
+test("compact settings tools keep closed schemas", () => {
+ const source = readFileSync(
+ resolve(root, "apps/backend/internal/mcp/server/settings_tools.go"),
+ "utf8",
+ );
+ for (const tool of [
+ "search_settings_kandev",
+ "describe_setting_kandev",
+ "get_settings_kandev",
+ "update_settings_kandev",
+ "list_settings_resources_kandev",
+ ]) {
+ assert.match(source, new RegExp(`NewToolWithRawSchema\\(\\n\\s*\\"${tool}\\"`));
+ }
+ assert.doesNotMatch(source, /WithEnum\(/);
+});