From 2fae22349995afc3ae7cd191e5166d738fc87ed6 Mon Sep 17 00:00:00 2001 From: Greg Allen Date: Wed, 1 Jul 2026 20:22:43 -0400 Subject: [PATCH] =?UTF-8?q?docs(adr):=20ADR=200064=20=E2=80=94=20deprecate?= =?UTF-8?q?=20customized/=20directory=20overlay?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Greg Allen Signed-off-by: Claude Opus 4.6 Signed-off-by: Greg Allen --- docs/ADRs/0035-layered-content-resolution.md | 4 +- ...-deprecate-customized-directory-overlay.md | 105 ++++++ docs/architecture.md | 5 +- .../deprecate-customized-directory-overlay.md | 299 ++++++++++++++++++ 4 files changed, 410 insertions(+), 3 deletions(-) create mode 100644 docs/ADRs/0064-deprecate-customized-directory-overlay.md create mode 100644 docs/plans/deprecate-customized-directory-overlay.md diff --git a/docs/ADRs/0035-layered-content-resolution.md b/docs/ADRs/0035-layered-content-resolution.md index e3ea761bfc..23f2fe0fb7 100644 --- a/docs/ADRs/0035-layered-content-resolution.md +++ b/docs/ADRs/0035-layered-content-resolution.md @@ -1,6 +1,6 @@ --- title: "35. Layered content resolution" -status: Accepted +status: Superseded relates_to: - agent-infrastructure - agent-architecture @@ -17,7 +17,7 @@ Date: 2026-05-09 ## Status -Accepted +Superseded by [ADR 0064](0064-deprecate-customized-directory-overlay.md). ## Context diff --git a/docs/ADRs/0064-deprecate-customized-directory-overlay.md b/docs/ADRs/0064-deprecate-customized-directory-overlay.md new file mode 100644 index 0000000000..341c09ac3a --- /dev/null +++ b/docs/ADRs/0064-deprecate-customized-directory-overlay.md @@ -0,0 +1,105 @@ +--- +title: "64. Deprecate customized/ directory overlay" +status: Accepted +relates_to: + - agent-infrastructure + - agent-architecture +topics: + - layering + - customization + - deprecation +--- + +# 64. Deprecate customized/ directory overlay + +Date: 2026-06-30 + +## Status + +Accepted + +Supersedes [ADR 0035](0035-layered-content-resolution.md) (layered content +resolution). + +## Context + +[ADR 0035](0035-layered-content-resolution.md) introduced a three-tier +layering model for agent customization: upstream defaults are copied into the +workspace at runtime, then files from `customized/` (per-org) or +`.fullsend/customized/` (per-repo) are overlaid on top, replacing upstream +files with matching names. The overlay is file-level replacement with no +field-level merging — customizing a single harness field requires copying the +entire upstream YAML and modifying it. + +Three subsequent ADRs have introduced mechanisms that cover every +customization scenario the overlay handled, with better ergonomics: + +- [ADR 0045](0045-forge-portable-harness-schema.md) added `base:` + composition for harness files. A thin wrapper inherits an upstream harness + by URL and overrides only the fields that differ, with proper merge + semantics (scalars override, skills concatenate, runner_env merges). + +- [ADR 0038](0038-universal-harness-access.md) added URL-based references + for declarative resources (agents, skills, policies, schemas). Resources + can be referenced from any trusted source without copying them into a + local directory. + +- [ADR 0058](0058-agent-registration.md) added config-based agent + registration. Agents are discovered from `agents:` entries in config + (URLs or local paths), not from directory scanning. + +Together these make the `customized/` directory overlay redundant: + +| What `customized/` did | Replacement | +|---|---| +| Override a harness | `base:` composition (ADR 0045) | +| Override an agent definition | Harness `agent:` field with path or URL (ADR 0038) | +| Add/remove agents | `agents:` list in config (ADR 0058) | +| Add custom skills | Harness `skills:` list with paths or URLs (ADR 0038); concatenated via `base:` (ADR 0045) | +| Override policies/schemas | Harness fields with paths or URLs (ADR 0038) | +| Custom scripts | `pre_script`/`post_script` in harness; inherited from `base:` (ADR 0045) | +| Custom env vars | `env:` in harness; merged via `base:` (ADR 0045) | +| Data files in `scripts/` (e.g. `.pre-commit-tools.yaml`) | L2 additive merge at repo root ([ADR 0056](0056-per-repo-precommit-tools-registry.md)); `base:` composition for harness-level overrides | + +**Scripts and env constraint:** +[ADR 0038](0038-universal-harness-access.md) prohibits standalone URL +references for executable resources. All script customization must go +through `base:` harness composition (where scripts declared in the base +are fetched from the same origin). The L1 full-replacement path for +data files like `.pre-commit-tools.yaml` via `customized/scripts/` +([ADR 0056](0056-per-repo-precommit-tools-registry.md)) is replaced by +the L2 additive merge at repo root, which already covers per-repo +customization without the overlay. + +The `customized/` directories currently contain only `.gitkeep` placeholders. +The overlay loop in reusable workflows runs every agent invocation but copies +zero files. + +## Decision + +Deprecate and remove the `customized/` directory overlay mechanism introduced +by ADR 0035. + +The implementation plan is in +[docs/plans/deprecate-customized-directory-overlay.md](../plans/deprecate-customized-directory-overlay.md). + +This ADR should be implemented once ADRs 0038, 0045, and 0058 are fully +implemented and in production. This deprecation is independent of +[ADR 0044](0044-deprecate-per-org-installation-mode.md) (deprecate per-org +installation mode) — the two may proceed in any order. If ADR 0044 completes +first, the per-org `customized/` path becomes moot and the scope here narrows +to per-repo only. + +## Consequences + +- Users who placed files in `customized/` must migrate to `base:` + composition, URL references, or config-based registration. +- Deprecation warnings during install and updated documentation will guide + migration. +- The reusable workflows become simpler — no overlay loop, no + `install_mode` branching for customization paths. +- The scaffold produces fewer files — no `.gitkeep` placeholders in + `customized/` subdirectories. +- `fullsend admin install` no longer creates `customized/` directories. +- A single, consistent customization model replaces the split between + directory overlay (ADR 0035) and harness composition (ADR 0045). diff --git a/docs/architecture.md b/docs/architecture.md index eeafec5474..1ebc53de87 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -386,7 +386,10 @@ See [ADR 0003](ADRs/0003-org-config-repo-convention.md) for the config repo conv [ADR 0047](ADRs/0047-vendored-installs-with-vendor-flag.md)). The scaffold installs only org-specific files and a `customized/` directory for org overrides. Org files in `customized/` overwrite upstream defaults at runtime - ([ADR 0035](ADRs/0035-layered-content-resolution.md)). + ([ADR 0035](ADRs/0035-layered-content-resolution.md)). The `customized/` + overlay is deprecated; `base:` harness composition, URL resource + references, and config-based agent registration now cover all customization + scenarios ([ADR 0064](ADRs/0064-deprecate-customized-directory-overlay.md)). ## Multi-org deployment model diff --git a/docs/plans/deprecate-customized-directory-overlay.md b/docs/plans/deprecate-customized-directory-overlay.md new file mode 100644 index 0000000000..181d4169f8 --- /dev/null +++ b/docs/plans/deprecate-customized-directory-overlay.md @@ -0,0 +1,299 @@ +# Implementation Plan: Deprecate customized/ directory overlay (ADR-0064) + +## Conventions + +Line numbers in this plan are pinned to the codebase at the time of +writing and will drift as PRs merge. Function and symbol names are +the primary references; line numbers are supplementary aids for initial +orientation. When implementing a PR, use the function/symbol name to +locate the current position rather than relying on line numbers. + +## Context + +ADR-0064 deprecates the `customized/` directory overlay mechanism +introduced by [ADR 0035](../ADRs/0035-layered-content-resolution.md). +The overlay is superseded by `base:` harness composition +([ADR 0045](../ADRs/0045-forge-portable-harness-schema.md)), URL-based +resource references ([ADR 0038](../ADRs/0038-universal-harness-access.md)), +and config-based agent registration +([ADR 0058](../ADRs/0058-agent-registration.md)). + +The `customized/` overlay touches these subsystems: + +| Subsystem | Key files | Surface | +|-----------|-----------|---------| +| Reusable workflows | `.github/workflows/reusable-{triage,code,review,fix,retro,prioritize}.yml` | `CUSTOM_BASE` overlay loop in workspace-prepare step | +| Scaffold workflow | `internal/scaffold/fullsend-repo/.github/workflows/repo-maintenance.yml` | Hardcoded `customized/scripts` overlay (not via `CUSTOM_BASE`) | +| Scaffold (Go) | `internal/scaffold/scaffold.go` | `layeredDirs`, `CustomizedDirs()`, `PerRepoCustomizedDirs()`, `isSkippedDir()`, `IsLayeredPath()` | +| Scaffold (install) | `internal/scaffold/installfiles.go` | `customizedDirsForPrefix()`, `.gitkeep` generation | +| Scaffold (vendor) | `internal/scaffold/vendorcontent.go` | `IsLayeredPath()` call | +| Scaffold (embed) | `internal/scaffold/fullsend-repo/customized/` | 8 empty subdirectories with `.gitkeep` files | +| Scaffold (data) | `internal/scaffold/fullsend-repo/scripts/.pre-commit-tools.yaml` | Comments documenting `customized/scripts/` as L1 override path | +| Harness wrappers | `internal/layers/harnesswrappers.go` | `wrapperHeader` comment referencing `customized/harness/` | +| User docs | `docs/guides/user/customizing-agents.md` | Guide pointing users to `customized/` | +| Agent docs | `docs/agents/README.md`, `docs/agents/{triage,review}.md` | References to `customized/` | +| Architecture docs | `docs/architecture.md`, `docs/runtimes.md` | References to layered content resolution | +| Other guides | `docs/guides/user/running-agents-locally.md`, `docs/guides/user/customizing-with-agents-md.md`, `docs/guides/user/customizing-with-skills.md`, `docs/guides/user/building-custom-agents.md`, `docs/guides/dev/cli-internals.md` | References to `customized/` | +| ADR cross-refs | `docs/ADRs/0033-*.md`, `0043-*.md`, `0044-*.md`, `0047-*.md`, `0053-*.md`, `0056-*.md`, `0059-*.md` | References to `customized/` directories or ADR 0035 | +| Other plans | `docs/plans/deprecate-per-org-install.md` | References to `customized/` copy step | + +## Prerequisites + +This work should begin once the following are fully implemented and in +production: + +- ADR 0045 (forge-portable harness schema) — all phases complete, + `base:` composition working in production +- ADR 0038 (universal harness access) — URL-based resource references + working in production +- ADR 0058 (agent registration) — config-based agent discovery working + in production + +## PR Dependency Graph + +``` +PR 1 (deprecation warnings) ──> PR 2 (remove overlay from workflows) + │ +PR 3 (remove scaffold code) ─────┤ + │ +PR 4 (update docs) ──────────────┤ + │ + └──> PR 5 (final cleanup + grep sweep) +``` + +PRs 2, 3, and 4 can be developed in parallel after PR 1 merges. PR 5 +is the final sweep after all prior PRs merge. + +--- + +## PR 1: Add deprecation warnings + +**Scope:** Emit warnings when `customized/` directories contain real +files. Zero behavioral change — the overlay still runs. + +**`internal/scaffold/installfiles.go`:** + +- In `CollectInstallFiles()` (~line 42) and `CollectPerRepoInstallFiles()` + (~line 79), continue generating `.gitkeep` files but add a comment + noting they will be removed in a future release. + +**Reusable workflows (all 6):** + +- After the `CUSTOM_BASE` overlay loop, add a step that checks whether + any non-`.gitkeep` files were copied. If so, emit a warning: + ``` + ::warning::Files in ${CUSTOM_BASE}/ are deprecated. Migrate to base: harness composition (ADR-0045). See docs/guides/user/customizing-agents.md + ``` + +**After merge:** Users with files in `customized/` see warnings in CI +logs. No behavioral change. + +--- + +## PR 2: Remove overlay loop from reusable workflows + +**Scope:** Remove the `CUSTOM_BASE` overlay from all 6 reusable +workflows. + +**`.github/workflows/reusable-triage.yml` (~lines 100–113):** +**`.github/workflows/reusable-code.yml` (~lines 102–113):** +**`.github/workflows/reusable-review.yml` (~lines 100–113):** +**`.github/workflows/reusable-fix.yml` (~lines 118–127):** +**`.github/workflows/reusable-retro.yml` (~lines 99–113):** +**`.github/workflows/reusable-prioritize.yml` (~lines 103–113):** + +In each workflow's "Prepare workspace" step, remove the block: + +```yaml +CUSTOM_BASE="customized" +if [[ "${INSTALL_MODE}" == "per-repo" ]]; then + CUSTOM_BASE=".fullsend/customized" +fi +for dir in ${LAYERED_DIRS}; do + if [[ -d "${CUSTOM_BASE}/${dir}" ]]; then + find "${CUSTOM_BASE}/${dir}" -type f ! -name '.gitkeep' -print0 \ + | while IFS= read -r -d '' f; do + rel="${f#"${CUSTOM_BASE}"/}" + mkdir -p "$(dirname "${rel}")" + cp "${f}" "${rel}" + done + fi +done +``` + +The upstream default copy loop (`for dir in ${LAYERED_DIRS}; do ... cp -r +"${SRC}/${dir}/." "${dir}/" ... done`) remains — it still populates the +workspace with upstream content. Only the customized overlay on top is +removed. + +**`internal/scaffold/fullsend-repo/.github/workflows/repo-maintenance.yml` +(~lines 57–63):** + +This workflow has its own hardcoded `customized/scripts` overlay that +does NOT use the `CUSTOM_BASE` variable. Remove the block: + +```yaml +if [[ -d "customized/scripts" ]]; then + find "customized/scripts" -type f ! -name '.gitkeep' -print0 \ + | while IFS= read -r -d '' f; do + rel="${f#customized/}" + ... + done +fi +``` + +**After merge:** Reusable workflows no longer overlay `customized/` +files. Any files users placed there are silently ignored (they should +have migrated after PR 1 warnings). + +--- + +## PR 3: Remove scaffold code for customized directories + +**Scope:** Remove Go code that generates and manages `customized/` +directories. + +**Delete embedded directories:** + +- `internal/scaffold/fullsend-repo/customized/` — the entire directory + tree (8 subdirectories, 8 `.gitkeep` files). + +**`internal/scaffold/scaffold.go`:** + +- Remove `CustomizedDirs()` (~line 117–125). +- Remove `PerRepoCustomizedDirs()` (~line 127–135). +- Update comment on `layeredDirs` (~line 57–59) to remove reference to + `customized//` and ADR 0035; reference ADR 0064 instead. + +**`internal/scaffold/installfiles.go`:** + +- Remove the `.gitkeep` generation loop in `CollectInstallFiles()` + (~lines 42–48) that calls `customizedDirsForPrefix()`. +- Remove the `.gitkeep` generation loop in `CollectPerRepoInstallFiles()` + (~lines 77–84) that calls `PerRepoCustomizedDirs()`. +- Remove `customizedDirsForPrefix()` (~lines 53–58). + +**`internal/layers/harnesswrappers.go`:** + +- Update `wrapperHeader` (~line 13) to remove the reference to + `customized/harness/` and ADR-0035. Replace with guidance pointing to + `base:` composition (ADR-0045). + +**`internal/scaffold/fullsend-repo/scripts/.pre-commit-tools.yaml` +(~lines 37–39):** + +- Remove comments documenting `customized/scripts/` as the L1 override + path. Update to reference L2 additive merge at repo root instead. + +**Test updates:** + +- `internal/scaffold/scaffold_test.go`: Remove assertions for + `CustomizedDirs()`, `PerRepoCustomizedDirs()`, and any tests that + verify `customized/` directory contents (including `scaffold_test.go` + assertion for `repo-maintenance.yml` overlay at ~line 735). +- `internal/scaffold/installfiles_test.go`: Remove assertions for + `.gitkeep` files in `customized/` paths. +- `internal/layers/harnesswrappers_test.go`: Update `wrapperHeader` + assertions if any. +- `internal/layers/workflows_test.go`: Remove assertion for + `customized/agents/.gitkeep` file mode (~line 455). +- `e2e/admin/admin_test.go`: Remove assertions for all 8 + `customized/*.gitkeep` files (~lines 173–180). + +**After merge:** `fullsend admin install` no longer creates `customized/` +directories. The scaffold embed no longer contains them. + +--- + +## PR 4: Update documentation + +**Scope:** Documentation-only. No code changes. + +**`docs/guides/user/customizing-agents.md`:** + +- Rewrite to present `base:` harness composition (ADR 0045) as the + primary customization mechanism. +- Remove all references to `customized/` directories. +- Add examples of thin harness wrappers with `base:` URLs. +- Add migration guidance for users who had files in `customized/`. + +**`docs/agents/triage.md`, `docs/agents/review.md`:** + +- Remove references to `customized/` if present. + +**`docs/architecture.md`:** + +- Update layered content resolution description to reflect that + `customized/` is removed. +- Reference ADR 0064 as superseding ADR 0035 for customization. + +**`docs/runtimes.md`:** + +- Update workspace preparation description to remove the overlay step. + +**`docs/guides/user/running-agents-locally.md`:** +**`docs/guides/user/customizing-with-agents-md.md`:** +**`docs/guides/user/customizing-with-skills.md`:** +**`docs/guides/user/building-custom-agents.md`:** +**`docs/guides/dev/cli-internals.md`:** + +- Remove or update references to `customized/` directories. + +**`docs/ADRs/0035-layered-content-resolution.md`:** + +- Add a note at the top of the Status section: "Superseded by + [ADR 0064](../ADRs/0064-deprecate-customized-directory-overlay.md)." +- Do not rewrite the body — ADRs are point-in-time records. + +**Other ADRs with cross-references:** + +- `0033-per-repo-installation-mode.md` +- `0043-managed-file-headers.md` +- `0044-deprecate-per-org-installation-mode.md` +- `0047-vendored-installs-with-vendor-flag.md` +- `0053-agent-driven-branch-targeting.md` +- `0056-per-repo-precommit-tools-registry.md` +- `0059-public-mint-mode-with-wildcard-allowlists.md` + +For each, add a brief annotation noting that `customized/` references +are superseded by ADR 0064. Do not rewrite ADR bodies. + +Note: ADRs 0036 and 0055 use "customized" only as an English word, not +as a path reference — they do not need updates. + +**`docs/plans/deprecate-per-org-install.md` (~lines 212–216):** + +- Add a supersession annotation noting that the `customized/` copy step + described in the migration command (PR 4) is superseded by ADR 0064. + +**`docs/plans/adr-0045-forge-portable-harness-phase2.md`:** + +- Update references to `customized/` if present. + +**After merge:** All documentation points to `base:` composition as the +customization mechanism. + +--- + +## PR 5: Final cleanup and grep sweep + +**Scope:** Final sweep. Depends on all prior PRs. + +**Grep sweep:** + +Run a final grep for stale references: + +```bash +grep -rn 'customized/' --include='*.go' --include='*.yml' --include='*.yaml' --include='*.md' --include='*.ts' --include='*.tsx' \ + | grep -v '.git/' | grep -v 'node_modules/' | grep -v 'CHANGELOG' +grep -rn 'CustomizedDirs\|PerRepoCustomizedDirs\|customizedDirsForPrefix' --include='*.go' +grep -rn 'CUSTOM_BASE' --include='*.yml' --include='*.yaml' +grep -rn 'ADR.0035\|ADR-0035\|adr.0035' --include='*.go' --include='*.yml' --include='*.yaml' +``` + +Fix or remove any remaining references. The `sentencetoken/token.go` +reference to "customized" is unrelated (it refers to prose +customization) and should be left alone. + +**After merge:** No stale references to `customized/` remain in the +codebase.