From 7c67f827a21fd187778c2a444eca975802537408 Mon Sep 17 00:00:00 2001 From: Fotis Stamatelopoulos Date: Fri, 8 May 2026 18:43:59 -0700 Subject: [PATCH 1/8] =?UTF-8?q?feat(6.8):=20role-template=20management=20U?= =?UTF-8?q?I=20=E2=80=94=20versioning=20+=20promote-to-production?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New top-level "Agents" tab in the web UI for editing the instruction templates each agent role reads. Each role gets: - A bundled cf² default (always selectable, read-only, never deletable). - Any number of saved versions stored under `~/.cfcf/templates-managed//{manifest.json, v_.md}`. - A "Promote to production" action that writes the selected version's content to `~/.cfcf/templates/` — the existing user-global override path that `getTemplate()` already reads. Reverting to default deletes the override file so cf² falls back to the embedded template. No runtime changes to agent spawning. Decoupled from the prior "blocked on 6.11/ADLC" framing: the user's vision (edit + version + promote) operates at per-role-template granularity — whatever role abstraction ADLC eventually settles on can layer on top of this without rework. **Shipped (round 1)** - `packages/core/src/role-templates.ts` — versioning manager. list / get / save / update / delete / promote, manifest self-heal on corruption, orphan detection, automatic revert when deleting the promoted version, automatic override-file refresh when editing it. Bundled defaults sourced via a new `getEmbeddedTemplate(name)` exported from `templates.ts`. - HTTP routes at `/api/role-templates/*` with uniform error envelope. - Web UI: new `/agents` route (Header link between Memory and Settings), tab strip across managed roles, version selector, monospace textarea editor, action buttons (Edit / Save as new version / Save changes / Promote / Revert / Delete), inline help block. Deep-linkable via `/agents?template=`. **Managed templates (round 1)**: cfcf-architect-instructions.md, cfcf-judge-instructions.md, cfcf-documenter-instructions.md, cfcf-reflection-instructions.md, process.md. **Out of scope (deferred follow-ups)**: dev-role custom-directions block (Tier-2 from the original 6.8 design — needs the sentinel-merge insertion-point design first), Product Architect / Help Assistant system-prompt management (their prompts are programmatically assembled), per-project override management UI, diff viewer, search-within-content. **Tests**: 30 unit tests in `role-templates.test.ts` (every flow + manifest corruption recovery + cross-template isolation), 15 endpoint tests in `routes/role-templates.test.ts`, 3 new route-parser tests for the new `/agents` + `?template=` routes. All 834 core+cli+web tests pass; clean typecheck; web build clean. Pre-existing `app.test.ts` config-merge failure on main is unrelated (verified earlier in this iter). **Design doc**: `docs/design/role-template-management.md`. Co-Authored-By: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 44 ++ docs/design/role-template-management.md | 190 +++++++ docs/plan.md | 4 +- packages/core/src/index.ts | 2 + packages/core/src/role-templates.test.ts | 304 +++++++++++ packages/core/src/role-templates.ts | 467 ++++++++++++++++ packages/core/src/templates.ts | 14 + packages/server/src/app.ts | 5 + .../server/src/routes/role-templates.test.ts | 243 +++++++++ packages/server/src/routes/role-templates.ts | 143 +++++ packages/web/src/App.tsx | 3 + packages/web/src/api.ts | 81 +++ packages/web/src/components/Header.tsx | 9 + packages/web/src/hooks/useRoute.test.ts | 23 + packages/web/src/hooks/useRoute.ts | 12 +- packages/web/src/pages/AgentTemplates.tsx | 512 ++++++++++++++++++ 16 files changed, 2053 insertions(+), 3 deletions(-) create mode 100644 docs/design/role-template-management.md create mode 100644 packages/core/src/role-templates.test.ts create mode 100644 packages/core/src/role-templates.ts create mode 100644 packages/server/src/routes/role-templates.test.ts create mode 100644 packages/server/src/routes/role-templates.ts create mode 100644 packages/web/src/pages/AgentTemplates.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index decdaf6..beda073 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,50 @@ Changes are tracked via git tags. Each release tag corresponds to an entry here. ## [Unreleased] +### Added — Item 6.8 (round 1): role-template management UI + +- **New top-level "Agents" tab** in the web UI (between Memory and + Settings). One sub-tab per managed role template; each tab shows + the template content in a scrollable monospace editor with version + selector, edit / save / promote / revert / delete actions, and an + inline help block. +- **Versioning + promote-to-production**: every role's bundled cf² + default is always selectable (read-only, never deletable). Saving + edits creates a new labelled version under + `~/.cfcf/templates-managed//`. Promoting a version writes its + content to the existing `~/.cfcf/templates/` user-global + override path that `getTemplate()` already reads — no runtime + changes to agent spawning. Reverting to default deletes the override + file so cf² falls back to the embedded default. Editing a + promoted version refreshes the override file in-place so the + change is live for the next agent run. +- **Managed templates (round 1)**: `cfcf-architect-instructions.md`, + `cfcf-judge-instructions.md`, `cfcf-documenter-instructions.md`, + `cfcf-reflection-instructions.md`, `process.md`. Per-project + overrides at `/cfcf-templates/` continue to take + precedence over the user-global override (the power-user escape + hatch, unmanaged from the UI). +- **HTTP API**: `GET /api/role-templates`, `GET .../:name`, + `GET .../:name/versions/:versionId`, `POST .../:name/versions`, + `PUT .../:name/versions/:versionId`, + `DELETE .../:name/versions/:versionId`, + `POST .../:name/promote`. Uniform `{ error: string }` envelope. +- **New core module** `packages/core/src/role-templates.ts` with + list / get / save / update / delete / promote helpers, manifest + self-heal on corruption, orphan detection. `getEmbeddedTemplate(name)` + newly exported from `templates.ts` for read-only access to the + bundled default. +- **Out of scope for round 1 (deferred follow-ups)**: dev-role + custom-directions block (Tier-2 from the original design — needs + the sentinel-merge insertion-point design first), Product Architect / + Help Assistant system-prompt management (their prompts are + programmatically assembled, not file-loaded), per-project override + management UI, diff viewer between versions. +- **Tests**: 30 unit tests in `role-templates.test.ts`, 15 endpoint + tests in `routes/role-templates.test.ts`, 3 new route-parser tests + for `/agents` + `?template=`. +- **Design doc**: [`docs/design/role-template-management.md`](docs/design/role-template-management.md). + ### Added — Item 6.33: ollama-models refresh - **Auto-refresh on server boot.** `cfcf server start` now calls diff --git a/docs/design/role-template-management.md b/docs/design/role-template-management.md new file mode 100644 index 0000000..e313fa6 --- /dev/null +++ b/docs/design/role-template-management.md @@ -0,0 +1,190 @@ +# Role-template management (item 6.8) — design + +## Problem + +cf² ships a fixed set of agent-role instruction templates (`cfcf-architect- +instructions.md`, `cfcf-judge-instructions.md`, `cfcf-documenter-instructions.md`, +`cfcf-reflection-instructions.md`, plus the workspace process template +`process.md`). Today users can override any of them by dropping a file into +`~/.cfcf/templates/` (user-global) or `/cfcf-templates/` +(project-local). The override is binary — one file wins; there's no way to +keep multiple drafts, revert easily, or compare against the bundled default. + +This design adds a **versioning + promote-to-production layer** on top of +the existing override mechanism, plus a web UI for editing. + +## Vision (from user, 2026-05-08) + +- New top-level **"Agents"** tab in the web UI. +- One sub-tab per role with the template content visible (scrollable, + searchable). +- Edit-and-save flow that creates **versions** rather than overwriting. +- Selector to view / load any saved version. +- **Promote-to-production** button — the promoted version is what cf² uses + at runtime. +- The bundled default is always available + promoteable (never deletable). + +## Constraints (existing system this needs to fit) + +- `getTemplate(name)` resolves: project-local → user-global → embedded + ([packages/core/src/templates.ts](../../packages/core/src/templates.ts)). +- The embedded default is compiled into the cfcf binary via `import ... + with { type: "text" }`. +- Sentinel-merge of ` ... ` (in + `CLAUDE.md` / `AGENTS.md`) is dev-agent-specific and lives in + `context-assembler.ts` — separate concern from this item. + +## Design + +### Two layers + +1. **Existing**: `~/.cfcf/templates/` is the single override file + `getTemplate()` reads. **Unchanged.** No runtime-code touched. +2. **New**: `~/.cfcf/templates-managed//` is a managed directory of + saved versions + a manifest pointer to which one is "promoted". The + manager writes the promoted version's content to + `~/.cfcf/templates/` (the existing override path) so the agent + runners pick it up automatically without any wiring change. + +### Storage layout + +``` +~/.cfcf/templates-managed/ + cfcf-architect-instructions.md/ + manifest.json { + currentVersionId: "v_" | "default", + versions: [ + { id, label, savedAt, contentHash } + ] + } + v_.md each saved version's content + cfcf-judge-instructions.md/ + ... +``` + +`"default"` is a sentinel value meaning "no override active". When a user +"promotes default", `~/.cfcf/templates/` is **deleted** so +`getTemplate` falls through to the embedded default. + +### Templates managed + +MVP scope: +- `cfcf-architect-instructions.md` +- `cfcf-judge-instructions.md` +- `cfcf-documenter-instructions.md` +- `cfcf-reflection-instructions.md` +- `process.md` (workspace process template) + +**Out of scope for MVP**: +- Dev role: no single template file (instructions are programmatically + generated by `context-assembler.generateInstructionContent()`). A + separate "custom directions" insertion-point design will follow. +- Product Architect / Help Assistant: their system prompts are + programmatically assembled, not single template files. +- Per-project (workspace-local) override management. The user-global + layer is the simpler scope for MVP; project-local stays the manual + power-user path (drop a file into `/cfcf-templates/`). + +### API + +`packages/core/src/role-templates.ts` exports: + +```ts +type TemplateManaged = { + name: string; // e.g. "cfcf-judge-instructions.md" + displayName: string; // human label e.g. "Judge" + defaultContent: string; // bundled default (read-only) + currentVersionId: string; // "default" | "v_" + currentContent: string; // resolved content currently in effect + versions: TemplateVersion[]; // saved user versions +}; + +type TemplateVersion = { + id: string; // "v_" + label: string; // user-supplied + savedAt: string; // ISO timestamp + contentHash: string; // sha256 short prefix +}; + +listManagedTemplates(): Promise +getManagedTemplate(name): Promise +saveVersion(name, { label, content }): Promise +updateVersion(name, versionId, { label?, content? }): Promise +deleteVersion(name, versionId): Promise +promoteVersion(name, versionId | "default"): Promise +getVersionContent(name, versionId | "default"): Promise +``` + +### HTTP endpoints + +- `GET /api/role-templates` → list of TemplateManaged (sans full content) +- `GET /api/role-templates/:name` → full TemplateManaged +- `GET /api/role-templates/:name/versions/:versionId` → { content } (versionId = "default" or "v_") +- `POST /api/role-templates/:name/versions` → { label, content } +- `PUT /api/role-templates/:name/versions/:versionId` → { label?, content? } +- `DELETE /api/role-templates/:name/versions/:versionId` → 204 +- `POST /api/role-templates/:name/promote` → { versionId } (or "default") + +### Web UI + +Top-level "Agents" route. Page renders left sidebar (role list) + main +panel (textarea + version selector + actions). + +Main panel sections: +1. **Heading**: role display name + "Currently in production: