Skip to content

Commit baf2b89

Browse files
committed
docs(adr): ADR 0064 — deprecate customized/ directory overlay
The customized/ directory overlay (ADR 0035) is superseded by base: harness composition (ADR 0045), URL-based resource references (ADR 0038), and config-based agent registration (ADR 0058). Add ADR 0064 to record this deprecation and a plan for removing the overlay plumbing. Signed-off-by: Greg Allen <gallen@redhat.com> Signed-off-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Greg Allen <gallen@redhat.com>
1 parent 1afea03 commit baf2b89

4 files changed

Lines changed: 364 additions & 3 deletions

File tree

docs/ADRs/0035-layered-content-resolution.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: "35. Layered content resolution"
3-
status: Accepted
3+
status: Superseded
44
relates_to:
55
- agent-infrastructure
66
- agent-architecture
@@ -17,7 +17,7 @@ Date: 2026-05-09
1717

1818
## Status
1919

20-
Accepted
20+
Superseded by [ADR 0064](0064-deprecate-customized-directory-overlay.md).
2121

2222
## Context
2323

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
---
2+
title: "64. Deprecate customized/ directory overlay"
3+
status: Accepted
4+
relates_to:
5+
- agent-infrastructure
6+
- agent-architecture
7+
topics:
8+
- layering
9+
- customization
10+
- deprecation
11+
---
12+
13+
# 64. Deprecate customized/ directory overlay
14+
15+
Date: 2026-06-30
16+
17+
## Status
18+
19+
Accepted
20+
21+
Supersedes [ADR 0035](0035-layered-content-resolution.md) (layered content
22+
resolution).
23+
24+
## Context
25+
26+
[ADR 0035](0035-layered-content-resolution.md) introduced a three-tier
27+
layering model for agent customization: upstream defaults are copied into the
28+
workspace at runtime, then files from `customized/` (per-org) or
29+
`.fullsend/customized/` (per-repo) are overlaid on top, replacing upstream
30+
files with matching names. The overlay is file-level replacement with no
31+
field-level merging — customizing a single harness field requires copying the
32+
entire upstream YAML and modifying it.
33+
34+
Three subsequent ADRs have introduced mechanisms that cover every
35+
customization scenario the overlay handled, with better ergonomics:
36+
37+
- [ADR 0045](0045-forge-portable-harness-schema.md) added `base:`
38+
composition for harness files. A thin wrapper inherits an upstream harness
39+
by URL and overrides only the fields that differ, with proper merge
40+
semantics (scalars override, skills concatenate, runner_env merges).
41+
42+
- [ADR 0038](0038-universal-harness-access.md) added URL-based references
43+
for declarative resources (agents, skills, policies, schemas). Resources
44+
can be referenced from any trusted source without copying them into a
45+
local directory.
46+
47+
- [ADR 0058](0058-agent-registration.md) added config-based agent
48+
registration. Agents are discovered from `agents:` entries in config
49+
(URLs or local paths), not from directory scanning.
50+
51+
Together these make the `customized/` directory overlay redundant:
52+
53+
| What `customized/` did | Replacement |
54+
|---|---|
55+
| Override a harness | `base:` composition (ADR 0045) |
56+
| Override an agent definition | Harness `agent:` field with path or URL (ADR 0038) |
57+
| Add/remove agents | `agents:` list in config (ADR 0058) |
58+
| Add custom skills | Harness `skills:` list with paths or URLs (ADR 0038); concatenated via `base:` (ADR 0045) |
59+
| Override policies/schemas | Harness fields with paths or URLs (ADR 0038) |
60+
| Custom scripts | `pre_script`/`post_script` in harness; inherited from `base:` (ADR 0045) |
61+
| Custom env vars | `env:` in harness; merged via `base:` (ADR 0045) |
62+
63+
The `customized/` directories currently contain only `.gitkeep` placeholders.
64+
The overlay loop in reusable workflows runs every agent invocation but copies
65+
zero files.
66+
67+
## Decision
68+
69+
Deprecate and remove the `customized/` directory overlay mechanism introduced
70+
by ADR 0035.
71+
72+
The implementation plan is in
73+
[docs/plans/deprecate-customized-directory-overlay.md](../plans/deprecate-customized-directory-overlay.md).
74+
75+
This ADR should be implemented once ADRs 0038, 0045, and 0058 are fully
76+
implemented and in production.
77+
78+
## Consequences
79+
80+
- Users who placed files in `customized/` must migrate to `base:`
81+
composition, URL references, or config-based registration.
82+
- Deprecation warnings during install and updated documentation will guide
83+
migration.
84+
- The reusable workflows become simpler — no overlay loop, no
85+
`install_mode` branching for customization paths.
86+
- The scaffold produces fewer files — no `.gitkeep` placeholders in
87+
`customized/` subdirectories.
88+
- `fullsend admin install` no longer creates `customized/` directories.
89+
- A single, consistent customization model replaces the split between
90+
directory overlay (ADR 0035) and harness composition (ADR 0045).

docs/architecture.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,10 @@ See [ADR 0003](ADRs/0003-org-config-repo-convention.md) for the config repo conv
385385
[ADR 0047](ADRs/0047-vendored-installs-with-vendor-flag.md)). The
386386
scaffold installs only org-specific files and a `customized/` directory for org
387387
overrides. Org files in `customized/` overwrite upstream defaults at runtime
388-
([ADR 0035](ADRs/0035-layered-content-resolution.md)).
388+
([ADR 0035](ADRs/0035-layered-content-resolution.md)). The `customized/`
389+
overlay is deprecated; `base:` harness composition, URL resource
390+
references, and config-based agent registration now cover all customization
391+
scenarios ([ADR 0064](ADRs/0064-deprecate-customized-directory-overlay.md)).
389392

390393
## Multi-org deployment model
391394

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
# Implementation Plan: Deprecate customized/ directory overlay (ADR-0064)
2+
3+
## Conventions
4+
5+
Line numbers in this plan are pinned to the codebase at the time of
6+
writing and will drift as PRs merge. Function and symbol names are
7+
the primary references; line numbers are supplementary aids for initial
8+
orientation. When implementing a PR, use the function/symbol name to
9+
locate the current position rather than relying on line numbers.
10+
11+
## Context
12+
13+
ADR-0064 deprecates the `customized/` directory overlay mechanism
14+
introduced by [ADR 0035](../ADRs/0035-layered-content-resolution.md).
15+
The overlay is superseded by `base:` harness composition
16+
([ADR 0045](../ADRs/0045-forge-portable-harness-schema.md)), URL-based
17+
resource references ([ADR 0038](../ADRs/0038-universal-harness-access.md)),
18+
and config-based agent registration
19+
([ADR 0058](../ADRs/0058-agent-registration.md)).
20+
21+
The `customized/` overlay touches these subsystems:
22+
23+
| Subsystem | Key files | Surface |
24+
|-----------|-----------|---------|
25+
| Reusable workflows | `.github/workflows/reusable-{triage,code,review,fix,retro,prioritize}.yml` | `CUSTOM_BASE` overlay loop in workspace-prepare step |
26+
| Scaffold (Go) | `internal/scaffold/scaffold.go` | `layeredDirs`, `CustomizedDirs()`, `PerRepoCustomizedDirs()`, `isSkippedDir()`, `IsLayeredPath()` |
27+
| Scaffold (install) | `internal/scaffold/installfiles.go` | `customizedDirsForPrefix()`, `.gitkeep` generation |
28+
| Scaffold (vendor) | `internal/scaffold/vendorcontent.go` | `IsLayeredPath()` call |
29+
| Scaffold (embed) | `internal/scaffold/fullsend-repo/customized/` | 8 empty subdirectories with `.gitkeep` files |
30+
| Harness wrappers | `internal/layers/harnesswrappers.go` | `wrapperHeader` comment referencing `customized/harness/` |
31+
| User docs | `docs/guides/user/customizing-agents.md` | Guide pointing users to `customized/` |
32+
| Agent docs | `docs/agents/README.md`, `docs/agents/{triage,review}.md` | References to `customized/` |
33+
| Architecture docs | `docs/architecture.md`, `docs/runtimes.md` | References to layered content resolution |
34+
| 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/` |
35+
| ADR cross-refs | `docs/ADRs/0033-*.md`, `0036-*.md`, `0043-*.md`, `0044-*.md`, `0047-*.md`, `0053-*.md`, `0055-*.md`, `0056-*.md`, `0059-*.md` | References to `customized/` directories or ADR 0035 |
36+
37+
## Prerequisites
38+
39+
This work should begin once the following are fully implemented and in
40+
production:
41+
42+
- ADR 0045 (forge-portable harness schema) — all phases complete,
43+
`base:` composition working in production
44+
- ADR 0038 (universal harness access) — URL-based resource references
45+
working in production
46+
- ADR 0058 (agent registration) — config-based agent discovery working
47+
in production
48+
49+
## PR Dependency Graph
50+
51+
```
52+
PR 1 (deprecation warnings) ──> PR 2 (remove overlay from workflows)
53+
54+
PR 3 (remove scaffold code) ─────┤
55+
56+
PR 4 (update docs) ──────────────┤
57+
58+
└──> PR 5 (final cleanup + grep sweep)
59+
```
60+
61+
PRs 2, 3, and 4 can be developed in parallel after PR 1 merges. PR 5
62+
is the final sweep after all prior PRs merge.
63+
64+
---
65+
66+
## PR 1: Add deprecation warnings
67+
68+
**Scope:** Emit warnings when `customized/` directories contain real
69+
files. Zero behavioral change — the overlay still runs.
70+
71+
**`internal/scaffold/installfiles.go`:**
72+
73+
- In `CollectInstallFiles()` (~line 42) and `CollectPerRepoInstallFiles()`
74+
(~line 79), continue generating `.gitkeep` files but add a comment
75+
noting they will be removed in a future release.
76+
77+
**Reusable workflows (all 6):**
78+
79+
- After the `CUSTOM_BASE` overlay loop, add a step that checks whether
80+
any non-`.gitkeep` files were copied. If so, emit a warning:
81+
```
82+
::warning::Files in ${CUSTOM_BASE}/ are deprecated. Migrate to base: harness composition (ADR-0045). See docs/guides/user/customizing-agents.md
83+
```
84+
85+
**After merge:** Users with files in `customized/` see warnings in CI
86+
logs. No behavioral change.
87+
88+
---
89+
90+
## PR 2: Remove overlay loop from reusable workflows
91+
92+
**Scope:** Remove the `CUSTOM_BASE` overlay from all 6 reusable
93+
workflows.
94+
95+
**`.github/workflows/reusable-triage.yml` (~lines 100–113):**
96+
**`.github/workflows/reusable-code.yml` (~lines 102–113):**
97+
**`.github/workflows/reusable-review.yml` (~lines 100–113):**
98+
**`.github/workflows/reusable-fix.yml` (~lines 118–127):**
99+
**`.github/workflows/reusable-retro.yml` (~lines 99–113):**
100+
**`.github/workflows/reusable-prioritize.yml` (~lines 103–113):**
101+
102+
In each workflow's "Prepare workspace" step, remove the block:
103+
104+
```yaml
105+
CUSTOM_BASE="customized"
106+
if [[ "${INSTALL_MODE}" == "per-repo" ]]; then
107+
CUSTOM_BASE=".fullsend/customized"
108+
fi
109+
for dir in ${LAYERED_DIRS}; do
110+
if [[ -d "${CUSTOM_BASE}/${dir}" ]]; do
111+
find "${CUSTOM_BASE}/${dir}" -type f ! -name '.gitkeep' -print0 \
112+
| while IFS= read -r -d '' f; do
113+
rel="${f#"${CUSTOM_BASE}"/}"
114+
mkdir -p "$(dirname "${rel}")"
115+
cp "${f}" "${rel}"
116+
done
117+
fi
118+
done
119+
```
120+
121+
The upstream default copy loop (`for dir in ${LAYERED_DIRS}; do ... cp -r
122+
"${SRC}/${dir}/." "${dir}/" ... done`) remains — it still populates the
123+
workspace with upstream content. Only the customized overlay on top is
124+
removed.
125+
126+
**After merge:** Reusable workflows no longer overlay `customized/`
127+
files. Any files users placed there are silently ignored (they should
128+
have migrated after PR 1 warnings).
129+
130+
---
131+
132+
## PR 3: Remove scaffold code for customized directories
133+
134+
**Scope:** Remove Go code that generates and manages `customized/`
135+
directories.
136+
137+
**Delete embedded directories:**
138+
139+
- `internal/scaffold/fullsend-repo/customized/` — the entire directory
140+
tree (8 subdirectories, 8 `.gitkeep` files).
141+
142+
**`internal/scaffold/scaffold.go`:**
143+
144+
- Remove `CustomizedDirs()` (~line 117–125).
145+
- Remove `PerRepoCustomizedDirs()` (~line 127–135).
146+
- Update comment on `layeredDirs` (~line 57–59) to remove reference to
147+
`customized/<dir>/` and ADR 0035; reference ADR 0064 instead.
148+
149+
**`internal/scaffold/installfiles.go`:**
150+
151+
- Remove the `.gitkeep` generation loop in `CollectInstallFiles()`
152+
(~lines 42–48) that calls `customizedDirsForPrefix()`.
153+
- Remove the `.gitkeep` generation loop in `CollectPerRepoInstallFiles()`
154+
(~lines 77–84) that calls `PerRepoCustomizedDirs()`.
155+
- Remove `customizedDirsForPrefix()` (~lines 53–58).
156+
157+
**`internal/layers/harnesswrappers.go`:**
158+
159+
- Update `wrapperHeader` (~line 13) to remove the reference to
160+
`customized/harness/` and ADR-0035. Replace with guidance pointing to
161+
`base:` composition (ADR-0045).
162+
163+
**Test updates:**
164+
165+
- `internal/scaffold/scaffold_test.go`: Remove assertions for
166+
`CustomizedDirs()`, `PerRepoCustomizedDirs()`, and any tests that
167+
verify `customized/` directory contents.
168+
- `internal/scaffold/installfiles_test.go`: Remove assertions for
169+
`.gitkeep` files in `customized/` paths.
170+
- `internal/layers/harnesswrappers_test.go`: Update `wrapperHeader`
171+
assertions if any.
172+
173+
**After merge:** `fullsend admin install` no longer creates `customized/`
174+
directories. The scaffold embed no longer contains them.
175+
176+
---
177+
178+
## PR 4: Update documentation
179+
180+
**Scope:** Documentation-only. No code changes.
181+
182+
**`docs/guides/user/customizing-agents.md`:**
183+
184+
- Rewrite to present `base:` harness composition (ADR 0045) as the
185+
primary customization mechanism.
186+
- Remove all references to `customized/` directories.
187+
- Add examples of thin harness wrappers with `base:` URLs.
188+
- Add migration guidance for users who had files in `customized/`.
189+
190+
**`docs/agents/README.md`:**
191+
192+
- Remove references to `customized/` overlay.
193+
- Update agent customization pointers to reference `base:` composition.
194+
195+
**`docs/agents/triage.md`, `docs/agents/review.md`:**
196+
197+
- Remove references to `customized/` if present.
198+
199+
**`docs/architecture.md`:**
200+
201+
- Update layered content resolution description to reflect that
202+
`customized/` is removed.
203+
- Reference ADR 0064 as superseding ADR 0035 for customization.
204+
205+
**`docs/runtimes.md`:**
206+
207+
- Update workspace preparation description to remove the overlay step.
208+
209+
**`docs/guides/user/running-agents-locally.md`:**
210+
**`docs/guides/user/customizing-with-agents-md.md`:**
211+
**`docs/guides/user/customizing-with-skills.md`:**
212+
**`docs/guides/user/building-custom-agents.md`:**
213+
**`docs/guides/dev/cli-internals.md`:**
214+
215+
- Remove or update references to `customized/` directories.
216+
217+
**`docs/ADRs/0035-layered-content-resolution.md`:**
218+
219+
- Add a note at the top of the Status section: "Superseded by
220+
[ADR 0064](../ADRs/0064-deprecate-customized-directory-overlay.md)."
221+
- Do not rewrite the body — ADRs are point-in-time records.
222+
223+
**Other ADRs with cross-references:**
224+
225+
- `0033-per-repo-installation-mode.md`
226+
- `0036-agent-execution-sandbox.md`
227+
- `0043-managed-file-headers.md`
228+
- `0044-deprecate-per-org-installation-mode.md`
229+
- `0047-vendored-installs-with-vendor-flag.md`
230+
- `0053-agent-driven-branch-targeting.md`
231+
- `0055-unified-env-var-delivery.md`
232+
- `0056-per-repo-precommit-tools-registry.md`
233+
- `0059-public-mint-mode-with-wildcard-allowlists.md`
234+
235+
For each, add a brief annotation noting that `customized/` references
236+
are superseded by ADR 0064. Do not rewrite ADR bodies.
237+
238+
**`docs/plans/adr-0045-forge-portable-harness-phase2.md`:**
239+
240+
- Update references to `customized/` if present.
241+
242+
**After merge:** All documentation points to `base:` composition as the
243+
customization mechanism.
244+
245+
---
246+
247+
## PR 5: Final cleanup and grep sweep
248+
249+
**Scope:** Final sweep. Depends on all prior PRs.
250+
251+
**Grep sweep:**
252+
253+
Run a final grep for stale references:
254+
255+
```bash
256+
grep -rn 'customized/' --include='*.go' --include='*.yml' --include='*.yaml' --include='*.md' --include='*.ts' --include='*.tsx' \
257+
| grep -v '.git/' | grep -v 'node_modules/' | grep -v 'CHANGELOG'
258+
grep -rn 'CustomizedDirs\|PerRepoCustomizedDirs\|customizedDirsForPrefix' --include='*.go'
259+
grep -rn 'CUSTOM_BASE' --include='*.yml' --include='*.yaml'
260+
grep -rn 'ADR.0035\|ADR-0035\|adr.0035' --include='*.go' --include='*.yml' --include='*.yaml'
261+
```
262+
263+
Fix or remove any remaining references. The `sentencetoken/token.go`
264+
reference to "customized" is unrelated (it refers to prose
265+
customization) and should be left alone.
266+
267+
**After merge:** No stale references to `customized/` remain in the
268+
codebase.

0 commit comments

Comments
 (0)