Skip to content

Commit fc679f5

Browse files
ggallenclaude
andcommitted
feat(cli): add migrate-customizations command with PR creation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Greg Allen <gallen@redhat.com>
1 parent 6cfeae9 commit fc679f5

24 files changed

Lines changed: 2710 additions & 14 deletions

docs/ADRs/0045-forge-portable-harness-schema.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,17 @@ forge-specific artifact. The harness and agent definition are portable.
588588
removing an agent is deleting a file, adding one is creating a thin
589589
wrapper with `base:`.
590590

591+
- **Bidirectional composition.** The `base:` merge semantics (scalars
592+
override, slices concatenate, maps merge, security fields never inherited)
593+
have an inverse: `DiffHarness` in `internal/harness/diff.go` computes
594+
the minimal child harness that reproduces a full harness when composed
595+
with a given base. This powers
596+
[ADR 0064](0064-deprecate-customized-directory-overlay.md)'s
597+
`migrate-customizations` command, which converts `customized/` directory
598+
overlays into `base:` composition harnesses. The diff engine mirrors
599+
`mergeBaseIntoChild` semantics exactly — changes to merge rules must be
600+
reflected in both directions.
601+
591602
- **Default URL allowlist for `base` composition.** `fullsend install`
592603
sets `allowed_remote_resources` in `config.yaml` to include the
593604
fullsend scaffold URL prefix

docs/ADRs/0064-deprecate-customized-directory-overlay.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ implemented and in production.
9090

9191
- Users who placed files in `customized/` must migrate to `base:`
9292
composition, URL references, or config-based registration.
93+
`fullsend agent migrate-customizations` automates this conversion and
94+
delivers the changes via pull request.
9395
- Deprecation warnings during install and updated documentation will guide
9496
migration.
9597
- The reusable workflows become simpler — no overlay loop, no

docs/architecture.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ Fullsend provides a base set of agent definitions. The adopting organization's *
242242
- Config-level agent registration: an `agents` list in both `OrgConfig` and `PerRepoConfig` declares agent harness sources as pinned URLs or local paths, replacing compiled-in agent discovery ([ADR 0058](ADRs/0058-agent-registration.md)).
243243
- Runtime resolution: `fullsend run <name>` looks up the agent in config and loads the harness directly from the URL or path — no intermediate wrapper files on disk. Role and slug come from the harness content itself.
244244
- Additive merge: config entries overlay scaffold-discovered agents (config wins on name collision), enabling gradual extraction of first-party agents without disrupting existing installations. Builds on [ADR 0045](ADRs/0045-forge-portable-harness-schema.md) harness identity model.
245-
- CLI management: `fullsend agent add/list/update/remove` manages config entries and auto-pins URLs to a commit SHA with an integrity hash.
245+
- CLI management: `fullsend agent add/list/update/remove/migrate-customizations` manages config entries and auto-pins URLs to a commit SHA with an integrity hash.
246246

247247
**Open questions:**
248248

docs/cli/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Download the latest binary from [GitHub Releases](https://github.com/fullsend-ai
2323
| Command | Description |
2424
|---------|-------------|
2525
| `fullsend run` | Execute an agent locally in a sandbox. See [running agents locally](../guides/user/running-agents-locally.md). |
26-
| `fullsend agent` | Manage agent registrations in config (add, list, update, remove) |
26+
| `fullsend agent` | Manage agent registrations in config (add, list, update, remove, migrate-customizations) |
2727
| `fullsend lock [agent-name]` | Pin remote dependencies to `lock.yaml` |
2828
| `fullsend scan` | Run security scanners on agent input/output |
2929

docs/guides/dev/cli-internals.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ fullsend
4242
│ ├── add <url-or-path> # Register an agent (URL auto-pinned)
4343
│ ├── list # List registered agents
4444
│ ├── update <name> [sha] # Re-pin URL agent to new commit SHA
45-
│ └── remove <name> # Unregister agent from config
45+
│ ├── remove <name> # Unregister agent from config
46+
│ └── migrate-customizations # Migrate customized/ → config agents
47+
│ ├── --fullsend-dir <dir> # Base directory with .fullsend layout
48+
│ ├── --repo <owner/repo> # Target repo for migration PR
49+
│ └── --dry-run # Preview changes without PR
4650
├── lock [agent-name] # Pin remote deps to lock.yaml
4751
│ ├── --all # Lock all harnesses in the harness directory
4852
│ ├── --fullsend-dir <path> # Base directory with .fullsend layout
@@ -85,6 +89,28 @@ fullsend
8589
└── --role <string> # Agent role for minting (required with --mint-url)
8690
```
8791

92+
### Migrate Customizations
93+
94+
The `fullsend agent migrate-customizations` command converts `customized/` directory overlays (deprecated by [ADR-0064](../../ADRs/0064-deprecate-customized-directory-overlay.md)) into config-driven agents with `base:` composition harnesses. It scans the local `customized/` directory, classifies each override, and delivers changes via PR:
95+
96+
```bash
97+
# Preview what would change (no PR created)
98+
fullsend agent migrate-customizations --fullsend-dir .fullsend --dry-run
99+
100+
# Create a migration PR
101+
fullsend agent migrate-customizations --fullsend-dir .fullsend --repo owner/repo
102+
```
103+
104+
Migration actions per agent:
105+
106+
| Override type | Detection | Action |
107+
|---------------|-----------|--------|
108+
| Dead | Agent already registered in config | Delete customized files |
109+
| Custom | Not in upstream scaffold | Move files, register local path in config |
110+
| Modified | Standard scaffold agent, not in config | Compute `base:` composition harness via `DiffHarness`, register in config |
111+
112+
The diff engine (`internal/harness/diff.go`) computes the minimal child harness that reproduces the customized version when composed with the upstream base. It mirrors `mergeBaseIntoChild` semantics: scalar overrides, slice concatenation extras, map merge deltas, and security fields always included.
113+
88114
### Command Decomposition
89115

90116
The `mint`, `inference`, and `github` subcommands decompose setup into role-specific operations for organizations that separate GCP and GitHub responsibilities:
@@ -549,6 +575,7 @@ var executableFiles = map[string]struct{}{
549575
|------|-------|---------|
550576
| `internal/cli/root.go` | ~34 | CLI entry point, command registration |
551577
| `internal/cli/admin.go` | ~2415 | Install/uninstall/analyze/enable/disable |
578+
| `internal/cli/migrate.go` | ~520 | Migrate customized/ overrides to config-driven agents |
552579
| `internal/cli/mint.go` | ~1022 | Mint deploy/enroll/unenroll/status |
553580
| `internal/cli/inference.go` | ~408 | Inference WIF provision/status |
554581
| `internal/cli/github.go` | ~966 | GitHub setup/set/status/uninstall/sync-scaffold/enroll/unenroll |

docs/guides/getting-started/operations.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ For organizations that separate GCP and GitHub responsibilities across teams, fu
7575
| Developer | `fullsend agent list` | List registered agents and their sources |
7676
| Developer | `fullsend agent update <name> [sha]` | Re-pin a URL agent to a new commit SHA |
7777
| Developer | `fullsend agent remove <name>` | Unregister an agent from config |
78+
| Developer | `fullsend agent migrate-customizations` | Migrate `customized/` overlays to config-driven agents via PR |
7879

7980
The typical handoff: a GCP admin runs `mint deploy` + `mint enroll` + `inference provision`, then passes the mint URL and WIF provider resource name to a GitHub maintainer who runs `github setup --mint-url=... --inference-wif-provider=...`.
8081

docs/guides/user/building-custom-agents.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Building custom agents
22

3+
> **Deprecated:** This guide uses the `customized/` directory overlay, which is
4+
> deprecated per [ADR-0064](../../ADRs/0064-deprecate-customized-directory-overlay.md).
5+
> For new custom agents, register them in `config.yaml` with a local `source:`
6+
> path instead. Run `fullsend agent migrate-customizations --dry-run` to
7+
> preview migrating existing customizations.
8+
39
This guide walks through creating a new custom agent from scratch on a per-repo fullsend installation.
410

511
For customizing existing agents (overriding harnesses, skills, or policies), see [Customizing agents](customizing-agents.md).

docs/guides/user/customizing-agents.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,17 @@ security: # Security is enabled by default with fail_mode
9595
9696
## Layered Configuration Resolution
9797
98+
> **Deprecated:** The `customized/` directory overlay mechanism described
99+
> below is deprecated per [ADR-0064](../../ADRs/0064-deprecate-customized-directory-overlay.md).
100+
> Use `base:` composition instead: register agents in `config.yaml` with a
101+
> `base:` URL pointing to the upstream harness, and override only the fields
102+
> that differ. See [ADR-0045](../../ADRs/0045-forge-portable-harness-schema.md)
103+
> for the composition model and [ADR-0058](../../ADRs/0058-agent-registration.md)
104+
> for config-driven registration.
105+
> Run `fullsend agent migrate-customizations --dry-run` to preview the
106+
> migration, then `fullsend agent migrate-customizations --repo owner/repo`
107+
> to apply it.
108+
98109
Fullsend uses a three-tier configuration inheritance model for all configuration: agent definitions, skills, policies, harness definitions, and guardrails. Each configuration tier can extend or override the one below it.
99110

100111
```
@@ -149,6 +160,9 @@ For per-repo mode, the same structure lives at `.fullsend/customized/` within th
149160

150161
### How Override Resolution Works
151162

163+
> **Deprecated:** This section describes the deprecated `customized/` overlay.
164+
> See the [deprecation notice above](#layered-configuration-resolution).
165+
152166
**File-level replacement, not field-level merging.** When you place a file in `customized/harness/code.yaml`, it completely replaces the upstream `harness/code.yaml`. There is no YAML field merging.
153167

154168
**Example: Adding a skill to the code agent**
@@ -190,6 +204,10 @@ To add a custom skill to the code agent's harness:
190204

191205
### Customizing Pre-commit Tool Dependencies
192206

207+
> **Note:** The `customized/scripts/.pre-commit-tools.yaml` L1 overlay path
208+
> referenced below uses the deprecated `customized/` mechanism.
209+
> The per-repo L2 path (`.pre-commit-tools.yaml` at repo root) is unaffected.
210+
193211
Fullsend auto-detects and installs tools required by a target repo's pre-commit hooks. The resolver reads `.pre-commit-config.yaml`, matches hooks against a tools registry, and installs missing dependencies before the authoritative pre-commit check runs.
194212

195213
Only hooks that pre-commit **cannot self-serve** need registry entries:

docs/guides/user/customizing-with-skills.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ when available.
116116

117117
## Overriding built-in skills
118118

119+
> **Deprecated:** The `customized/` overlay described below is deprecated per
120+
> [ADR-0064](../../ADRs/0064-deprecate-customized-directory-overlay.md).
121+
> Use `base:` composition and config-driven agent registration instead.
122+
119123
To intentionally **replace** a built-in skill with your own version, use the
120124
`customized/` overlay ([ADR 0035](../../ADRs/0035-layered-content-resolution.md)).
121125
This replaces the skill at the config layer before the agent starts — the

docs/guides/user/running-agents-locally.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,11 @@ cp -r /tmp/fullsend-ai_fullsend/internal/scaffold/fullsend-repo/. /tmp/agents/
274274

275275
Then apply your organization customizations, if any:
276276

277+
> **Note:** The `customized/` overlay mechanism is deprecated per
278+
> [ADR-0064](../../ADRs/0064-deprecate-customized-directory-overlay.md).
279+
> Orgs that have migrated to config-driven agents should skip these
280+
> `cp -r customized/` steps and use the registered harness paths directly.
281+
277282
```bash
278283
git clone --depth 1 https://github.com/{org}/.fullsend.git /tmp/org-fullsend/
279284
cp -r /tmp/org-fullsend/customized/. /tmp/agents/

0 commit comments

Comments
 (0)