Skip to content

Commit 2dba294

Browse files
committed
docs: add ADR and implementation plan for config-driven agents
Agents are currently compiled into the fullsend binary (scaffold embed + hardcoded externalAgents map). This ADR proposes making agents a config-level concept in both org and per-repo config, so first-party and third-party agents use the same mechanism and users can add agents to their repo without code changes. The implementation plan breaks the work into five phases: config schema, CLI commands, wrapper generation from config, cleanup, and transition to authoritative config. 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 08e7c62 commit 2dba294

2 files changed

Lines changed: 616 additions & 0 deletions

File tree

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
---
2+
title: "NNNN. Config-driven agents"
3+
status: Accepted
4+
relates_to:
5+
- agent-architecture
6+
- agent-infrastructure
7+
topics:
8+
- agents
9+
- per-repo
10+
- configuration
11+
- extensibility
12+
---
13+
14+
# NNNN. Config-driven agents
15+
16+
Date: 2026-06-29
17+
18+
## Status
19+
20+
Accepted
21+
22+
## Context
23+
24+
Which agents fullsend knows about is currently compiled into the binary.
25+
Scaffold-embedded harnesses (`internal/scaffold/fullsend-repo/harness/`)
26+
define the canonical agent set, and a hardcoded `externalAgents` map in
27+
`baseurl.go` extends it for agents extracted to standalone repos. Both
28+
`HarnessNames()` and `HarnessWrappersLayer` read from these compiled-in
29+
sources to enumerate and generate harness wrappers.
30+
31+
This creates three problems:
32+
33+
1. **Adding an agent requires a code change.** A user who wants to run a
34+
custom agent must modify the fullsend binary or work around it.
35+
2. **First-party agents extracted to external repos need special
36+
handling.** The `externalAgents` map is a one-off mechanism that pins
37+
commit SHAs and content hashes in Go source.
38+
3. **First-party and third-party agents follow different paths.**
39+
Fullsend's own agents are discovered from the scaffold embed;
40+
external agents are discovered from a hardcoded map. There is no
41+
single, uniform mechanism.
42+
43+
The triage agent extraction to `fullsend-ai/agents`
44+
([ADR 0045](0045-forge-portable-harness-schema.md) Phase 4) is the
45+
first agent to move out of the scaffold. More will follow. The
46+
registration mechanism must support both first-party extractions and
47+
user-defined agents without code changes to fullsend.
48+
49+
## Decision
50+
51+
Make agent registration a **config-level concept** in both org config
52+
and per-repo config.
53+
54+
**Config schema.** Add an `agents` list to both `OrgConfig` and
55+
`PerRepoConfig`. Each entry is either a string shorthand or an object
56+
with an explicit name. The source can be a URL (for remote harnesses)
57+
or a local path (for harnesses on disk):
58+
59+
```yaml
60+
# Per-repo config (.fullsend/config.yaml in target repo)
61+
version: "1"
62+
agents:
63+
# String shorthand — name derived from filename
64+
- https://raw.githubusercontent.com/fullsend-ai/fullsend/<sha>/internal/scaffold/fullsend-repo/harness/code.yaml#sha256=<hash>
65+
- harness/my-custom-agent.yaml
66+
67+
# Object form — explicit name overrides filename
68+
- name: triage
69+
source: https://raw.githubusercontent.com/fullsend-ai/agents/<sha>/harness/triage.yaml#sha256=<hash>
70+
- name: lint
71+
source: harness/my-linter.yaml
72+
allowed_remote_resources:
73+
- https://raw.githubusercontent.com/fullsend-ai/fullsend/
74+
- https://raw.githubusercontent.com/fullsend-ai/agents/
75+
```
76+
77+
An entry's source is treated as a URL if it starts with `https://`,
78+
and as a local path otherwise. Local paths resolve relative to the
79+
`.fullsend/` directory. When `name` is omitted (string shorthand), the
80+
agent name is derived from the filename (`triage.yaml` -> `triage`).
81+
When `name` is provided, it overrides the filename-derived name. Role
82+
and slug are read from the harness content at
83+
install/wrapper-generation time, not stored in config. URL entries
84+
include an integrity hash fragment for content verification
85+
([ADR 0038](0038-universal-harness-access.md)); local paths do not
86+
require one since the content is already trusted on disk.
87+
88+
**`allowed_remote_resources` in per-repo config.** This field currently
89+
exists only in org config. Per-repo config gains it to support base
90+
composition without an org config repo. Both are checked at load time;
91+
per-repo entries are additive.
92+
93+
**Install seeding.** During install, the default first-party agent
94+
URLs are populated into `agents` — in org config for org-mode
95+
installs (`fullsend admin install <org>`), in per-repo config for
96+
per-repo installs (`fullsend github` / `fullsend admin install
97+
<owner/repo>`). They use the same format as any user-added agent. The
98+
`--agents` flag continues to control which roles are installed; the
99+
mapping from role to default harness URL is a build-time constant (not
100+
a runtime concept).
101+
102+
**CLI surface.** A `fullsend agent` subcommand group manages the
103+
agents list in config:
104+
105+
| Command | Effect |
106+
|---------|--------|
107+
| `fullsend agent add <url-or-path>` | Fetch/read harness, validate, append to config |
108+
| `fullsend agent list` | List registered agents with name, role, source |
109+
| `fullsend agent update <name> [sha]` | Re-pin agent to latest HEAD or a specific commit |
110+
| `fullsend agent remove <name>` | Remove agent entry from config |
111+
112+
`agent add` accepts a URL or a local path and validates the harness
113+
before appending it to config. `agent update` re-pins a URL-based
114+
agent to a new commit (latest HEAD or a specific SHA). Both commands
115+
automatically resolve unpinned URLs to fully pinned form — commit SHA
116+
and integrity hash are resolved and computed by the CLI so users never
117+
need to construct pinned URLs manually. The stored config entry is
118+
always fully pinned.
119+
120+
**Additive merge model.** Config entries are merged with
121+
scaffold-discovered agents, not a replacement. Scaffold agents form
122+
the base set; config entries add new agents or override scaffold
123+
entries with the same name. The merge rule: config wins over scaffold
124+
when names collide. This enables gradual migration — agents can be
125+
extracted one at a time without requiring every config to list all
126+
agents.
127+
128+
`fullsend agent list` shows the merged view (scaffold + config) so
129+
the full agent set is visible in one place.
130+
131+
**Wrapper generation.** `HarnessWrappersLayer` (org mode) builds the
132+
merged agent set and generates wrappers from it. Per-repo install
133+
does the same. For URL entries, both generate the same thin wrapper
134+
format (`base:` + `role:` + `slug:`). For local path entries, the
135+
harness file is used directly — no wrapper is needed since the
136+
content is already on disk.
137+
138+
**Removal of compiled-in agent map.** The `externalAgents` map,
139+
`IsExternalAgent()`, and the external-agent branches in
140+
`HarnessBaseURL()`/`HarnessContentHash()` are deleted.
141+
`HarnessNames()` returns only scaffold-embedded names (used as the
142+
base set for the additive merge).
143+
144+
**Transition to authoritative config.** The additive model is a
145+
migration aid. Once all first-party agents have been extracted from
146+
the scaffold and all installations have populated `agents` in config,
147+
a follow-up change makes config authoritative: scaffold agents are no
148+
longer discovered, and `agents` is the complete list. An issue will
149+
be filed to track this transition once the last agent is extracted.
150+
151+
## Consequences
152+
153+
- **Extensibility.** Anyone can add an agent to the fullsend installation in their repo with
154+
`fullsend agent add <url-or-path>` — no code change, no PR to
155+
fullsend. Local paths support development and private harnesses.
156+
- **Uniform path.** First-party and third-party agents are registered
157+
the same way. Extracting an agent to a standalone repo is a config
158+
update, not a code change.
159+
- **Gradual migration.** The additive merge model means agents can be
160+
extracted from the scaffold one at a time. Users only need config
161+
entries for agents that have moved or been added — unchanged
162+
scaffold agents continue to work. Once all agents are extracted,
163+
config becomes authoritative and the scaffold fallback is removed.
164+
- **Org config dependency removed for per-repo installs.**
165+
`allowed_remote_resources` in per-repo config eliminates the need
166+
to read org config for base composition validation.
167+
- **Migration.** No forced migration. Existing installations continue
168+
to work without changes:
169+
- When `agents` is empty in config, the code falls back to the
170+
current scaffold-based agent discovery. This fallback is
171+
permanent until the config is populated — there is no deadline.
172+
- Per-repo configs that lack `allowed_remote_resources` inherit
173+
the org-level allowlist (if present) or use the scaffold
174+
fallback path, which does not require an allowlist.
175+
- To opt in, users can run `fullsend agent add` to populate the
176+
list manually, or the config is backfilled automatically the
177+
next time they run `fullsend admin install --upgrade`,
178+
`fullsend github` (re-install), or `fullsend repos sync`
179+
([ADR 0057](0057-repos-management.md)).
180+
- A deprecation notice is logged when the fallback is used, to
181+
nudge users toward populating the config.
182+
183+
## References
184+
185+
- [ADR 0033](0033-per-repo-installation-mode.md) -- per-repo installation mode
186+
- [ADR 0038](0038-universal-harness-access.md) -- URL-based resource references and integrity hashes
187+
- [ADR 0045](0045-forge-portable-harness-schema.md) -- harness composition via `base:` URLs
188+
- [ADR 0057](0057-repos-management.md) -- repos management for per-repo installations
189+
- [Implementation plan](../plans/config-driven-agents.md)

0 commit comments

Comments
 (0)