Summary
Externalize the definition of target architectures into a single declarative registry/config so adding a new target (e.g. the proposed "generic agent" in #19, or Copilot Studio) is a one-place change — no scattered edits across an enum, a UI array, a catalogue switch, and an automation lookup.
Problem — a new target touches 4+ places today
Adding or enabling an architecture currently requires hand-editing several disconnected spots:
common/skill.ts — extend the SkillArchitecture zod enum and add an entry to the ARCHITECTURES selector array.
electron/skillbuilder/<name>-catalog.ts — author a new capability-catalogue module (+ a *_CATALOGUE_VERSION).
electron/skillbuilder/scout-catalog.ts — add a case to the catalogueFor(architecture) switch.
electron/automationbuilder/scout-automation-catalog.ts — add a branch to automationCatalogueFor(architecture).
These are easy to miss and keep in sync (e.g. an architecture can be in the enum but fall through catalogueFor to null, which the builder surfaces as "That target architecture isn't available yet.").
Proposed approach
Introduce one architecture registry — a single source of truth that carries everything about a target:
interface ArchitectureDefinition {
id: string; // "scout" | "cowork" | ...
label: string;
enabled: boolean;
note: string; // shown under the selector option
catalogueVersion: string;
skillCatalogue: () => string; // capability catalogue text (main-only)
automationCatalogue?: () => string; // optional; automations are Scout-only today
}
Then derive the existing surfaces from it instead of maintaining them by hand:
SkillArchitecture (the union type / enum) is derived from the registry's ids.
ARCHITECTURES (UI metadata) is a projection of the registry.
catalogueFor / automationCatalogueFor become simple registry lookups (no per-target switch).
Adding a target = add one registry entry (+ author its catalogue content). #19's "generic agent" would just be one more entry with a neutral catalogue.
Constraints to preserve
- Ship catalogues with the app, no runtime fetch. Catalogues are static, versioned snapshots embedded in the system prompt (end users don't have the Scout repo checked out) — keep them bundled and keep the "built-ins only" authoring rule.
- Keep the main/renderer split. UI metadata (
id/label/enabled/note) is safe for the renderer and lives in common/; the catalogue payload is main-process only. The registry should expose the public metadata without leaking catalogue text to the renderer.
- Don't lose type safety. Prefer a single
as const source array so the SkillArchitecture union is still inferred at compile time; otherwise widen to string + runtime validation (zod) at the boundaries.
Acceptance criteria
- Adding/enabling a target architecture requires editing one registry location (plus authoring its catalogue content) — no manual edits to
catalogueFor, automationCatalogueFor, the enum, or ARCHITECTURES.
- Existing
scout / cowork / copilot-studio behavior and catalogues are unchanged.
- The renderer still receives only UI metadata, never catalogue text.
- It's impossible to have an "enabled" target with no catalogue wired (registry makes the pairing explicit).
Open questions
- Config format: a TS module registry (keeps type inference, loaders, and bundling) vs. external JSON/YAML data (more literally "configuration", but needs a load/validate + bundling strategy and loses inline TS).
- Should catalogue content stay in separate files referenced by the registry entry (they're large), or move inline?
- Is per-target automation support worth modeling now (optional field) or deferred until a second automation-capable target exists?
Related: #19 (add a "generic agent" target) — that target becomes a trivial registry entry once this lands.
Summary
Externalize the definition of target architectures into a single declarative registry/config so adding a new target (e.g. the proposed "generic agent" in #19, or Copilot Studio) is a one-place change — no scattered edits across an enum, a UI array, a catalogue
switch, and an automation lookup.Problem — a new target touches 4+ places today
Adding or enabling an architecture currently requires hand-editing several disconnected spots:
common/skill.ts— extend theSkillArchitecturezod enum and add an entry to theARCHITECTURESselector array.electron/skillbuilder/<name>-catalog.ts— author a new capability-catalogue module (+ a*_CATALOGUE_VERSION).electron/skillbuilder/scout-catalog.ts— add acaseto thecatalogueFor(architecture)switch.electron/automationbuilder/scout-automation-catalog.ts— add a branch toautomationCatalogueFor(architecture).These are easy to miss and keep in sync (e.g. an architecture can be in the enum but fall through
catalogueFortonull, which the builder surfaces as "That target architecture isn't available yet.").Proposed approach
Introduce one architecture registry — a single source of truth that carries everything about a target:
Then derive the existing surfaces from it instead of maintaining them by hand:
SkillArchitecture(the union type / enum) is derived from the registry'sids.ARCHITECTURES(UI metadata) is a projection of the registry.catalogueFor/automationCatalogueForbecome simple registry lookups (no per-targetswitch).Adding a target = add one registry entry (+ author its catalogue content). #19's "generic agent" would just be one more entry with a neutral catalogue.
Constraints to preserve
id/label/enabled/note) is safe for the renderer and lives incommon/; the catalogue payload is main-process only. The registry should expose the public metadata without leaking catalogue text to the renderer.as constsource array so theSkillArchitectureunion is still inferred at compile time; otherwise widen tostring+ runtime validation (zod) at the boundaries.Acceptance criteria
catalogueFor,automationCatalogueFor, the enum, orARCHITECTURES.scout/cowork/copilot-studiobehavior and catalogues are unchanged.Open questions
Related: #19 (add a "generic agent" target) — that target becomes a trivial registry entry once this lands.