What happens
Adding a custom agent to a fullsend installation today requires five steps in the .fullsend repo:
- Allowlist the agent's source domain in
config.yaml allowed_remote_resources
- Enable the role in
config.yaml defaults.roles
- Add a harness file (e.g.
customized/harness/uber.yaml) referencing the remote agent definition, skills, and policy
- Add a GitHub Actions workflow file (e.g.
.github/workflows/uber.yml) with a # fullsend-stage: marker that calls a reusable workflow
- Add dispatch routing logic to
dispatch.yml (or rely on a slash command) so events reach the new stage
Steps (4) and (5) are boilerplate. The workflow file is a thin shim that passes inputs to a reusable workflow and names the harness. The dispatch routing wires events to the stage. Neither contains agent-specific logic — they exist only because the dispatch router discovers agents by scanning workflow files for # fullsend-stage: markers.
A second friction point: ValidRoles() in internal/config/config.go is a hardcoded allowlist. Custom roles fail config validation without modifying the fullsend binary.
What should happen
Steps (4) and (5) should be expressible entirely via the harness file in step (3). An org admin adding a custom agent should only need to:
- Allowlist the source in
config.yaml
- Enable the role in
config.yaml
- Add a harness file
The harness YAML would declare its trigger conditions, e.g.:
agent: https://raw.githubusercontent.com/ralphbean/uber-agent/<commit>/agents/uber.md#sha256=abc123...
triggers:
- event: issues
action: labeled
label: needs-uber
- event: issue_comment
command: /fs-uber
# ...
The dispatch router would read trigger declarations from harness files at dispatch time instead of scanning workflow files for stage markers. A single generic reusable workflow would handle execution for any harness.
ValidRoles() should accept any role matching ^[a-z][a-z0-9_-]*$ that has a corresponding harness file, rather than requiring the role to be in a hardcoded list.
Context
This is a prerequisite for making third-party agent installation simple enough that an org admin can drop in an external agent (e.g. from github.com/ralphbean/uber-agent) with minimal configuration. It also sets the stage for re-platforming fullsend's default agents to use the same mechanism.
Related:
What happens
Adding a custom agent to a fullsend installation today requires five steps in the
.fullsendrepo:config.yamlallowed_remote_resourcesconfig.yamldefaults.rolescustomized/harness/uber.yaml) referencing the remote agent definition, skills, and policy.github/workflows/uber.yml) with a# fullsend-stage:marker that calls a reusable workflowdispatch.yml(or rely on a slash command) so events reach the new stageSteps (4) and (5) are boilerplate. The workflow file is a thin shim that passes inputs to a reusable workflow and names the harness. The dispatch routing wires events to the stage. Neither contains agent-specific logic — they exist only because the dispatch router discovers agents by scanning workflow files for
# fullsend-stage:markers.A second friction point:
ValidRoles()ininternal/config/config.gois a hardcoded allowlist. Custom roles fail config validation without modifying the fullsend binary.What should happen
Steps (4) and (5) should be expressible entirely via the harness file in step (3). An org admin adding a custom agent should only need to:
config.yamlconfig.yamlThe harness YAML would declare its trigger conditions, e.g.:
The dispatch router would read trigger declarations from harness files at dispatch time instead of scanning workflow files for stage markers. A single generic reusable workflow would handle execution for any harness.
ValidRoles()should accept any role matching^[a-z][a-z0-9_-]*$that has a corresponding harness file, rather than requiring the role to be in a hardcoded list.Context
This is a prerequisite for making third-party agent installation simple enough that an org admin can drop in an external agent (e.g. from
github.com/ralphbean/uber-agent) with minimal configuration. It also sets the stage for re-platforming fullsend's default agents to use the same mechanism.Related: