Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions docs/ADRs/0043-automatic-updates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
title: "43. Automatic Updates"
status: Accepted
relates_to: []
topics:
- versioning
- updates
- automatic updates
---

# 43. Automatic Updates

Date: 2026-06-09

## Status

Accepted

<!-- ADRs are point-in-time records, but not fully frozen after acceptance.
Minor annotations are welcome: cross-references to related ADRs, short
notes linking to newer decisions, or clarifying remarks. However, do not
substantially rewrite the Context, Decision, or Consequences sections. If
the decision itself needs to change, write a new ADR that supersedes this
one. For evolving design narrative, use docs/architecture.md. -->

## Context

Currently Fullsend uses a moving tag (`v0`) so users pick up the latest changes. When a release happens
a new tag `vMAJOR.MINOR.PATCH` gets created and the moving tag gets moved to the same SHA. New Fullsend
runs pick up these changes as they use the moving tag. Fullsend also uses `latest` as a binary
version by default, so users automatically pick up new changes for the binary as well.

On the one hand we have concerns about breaking people when releasing new stuff, as things break in
unexpected ways, and tests do not catch those. On the other hand there are people willing to accept
updates and deal with the consequences later.

There are also infrastructure problems. What happens when the update include a new variable
that needs to be present in the platform of choice? There are external changes like those
that make automatic update a challenge.

## Decision

Our decision is to provide two tags:

* Moving tag that tracks the latest release (probably called `latest`).
* Version tags that track releases (`vMAJOR.MINOR.PATCH` which area already created).

By default Fullsend should be installed in a way that it tracks the binary version (`fullsend --version`).
Users should explicitly change something to track a new version tag or the moving tag.

Fullsend must make users aware of the implications of choosing a moving tag:

* Broken releases.
* Infrastructure changes required.

## Consequences

* `v0` should be migrated to the new moving tag and deleted.
* Current users track the new floating tag automatically to keep behavior consistent.
* New users track the version tag they install at.

See [Automatic Updates](../plans/automatic-updates.md) for the design details.
116 changes: 116 additions & 0 deletions docs/plans/automatic-updates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Design Document: Automatic Updates

[ADR 43](../ADRs/0043-automatic-updates.md) decision is to implement a system that
uses a single tag to control all the components' version Fullsend uses. This design
document describes in detail the current state and the desired implementation:

## Current state

Currently there are four versions within Fullsend system:

* Reusable Workflows: jobs use the line
`uses: fullsend-ai/fullsend/.github/workflows/reusable-dispatch.yml@v0`
to pull reusable workflows from Fullsend. This is hard-coded as it can't be templated with
an expression.
* CLI: the `action.yml` YAML in the root of the repository uses
`inputs.version` (defaults to `latest`). This is passed around.
* GH Actions: reusable workflows clone the `fullsend-ai/.fullsend` repository
at it's `inputs.fullsend_ai_ref` (defaults to `v0`) and use the actions with a
relative path: `uses: ./.defaults/.github/actions/validate-enrollment`. This
is passed around.
* OpenShell sandbox images: currently images use the `latest` tag and can't be
templated as harnesses and `fullsend run` do not allow for that. These have no Semver
tags.

When we release, we create a new Semver tag (`vMAJOR.MINOR.PACTH`) and move the `v0` tag
to the new Semver tag. As users have configured `v0` for workflows and actions, and
`latest` for the binary, they get automatically the new changes.

To change versions in repository mode you change your `.github/workflows/fullsend.yaml`.
First the `uses: ... reusable-dispatch.yml@v0` needs to reference your version. Then
the `fullsend_ai_ref` passed should be changed. Finally you add `fullsend_version` to
that job and set it to the proper version.

To change versions in org mode you change the call to the reusable workflows each one of
your workflows on `.fullsend` (`fix.yaml`, `triage.yaml`) do. The changes required are the
same as in repository mode, just in a different file.

## Implementation

With `fullsend_ai_ref` and `fullsend_version` it is easy to control from a single
place which version should be use. A step in the shim would pull the version
from the `config.yaml` and will pass it around. However the reusable workflows can't
benefit from this.

So the version pinning should happen another way. We will introduce a new parameter
called `--upstream-ref` to both `admin install` and `github setup` that accepts
a reference to `fullsend-ai/fullsend`. By default the value is pulled from the
`cli.Version` variable injected at compile time. If any other value is specified
then it is used.

This value (`upstreamRef`) would be used to template the following files:

* `internal/scaffold/fullsend-repo/templates/shim-per-repo.yaml` (it becomes
`.github/workflows/fullsend.yaml` in per-repo mode).
* `internal/scaffold/fullsend-repo/.github/workflows/*.yml` (it becomes
`.github/workflows/*.yml` on per-org mode)

So every call to reusable workflows should be templated (regardless of the install mode).
The template string will be `__FULLSEND_REF__`.

Given that we are changing this code, we may as well update the variable names to reflect
better their real usage:

* `fullsend_ai_ref` -> `fullsend_actions_ref`
* `fullsend_version` -> `fullsend_cli_ref`

So the template looks like (excluding other details):

```yaml
# fullsend.yaml or <stage>.yml
uses: fullsend-ai/fullsend/.../reusable-*.yml@__FULLSEND_REF__
with:
fullsend_actions_ref: __FULLSEND_REF__
fullsend_cli_ref: __FULLSEND_REF__
```

Running `fullsend github setup org/repo --upstream-ref latest` the template will be rendered
as (excluding other details):

```yaml
# fullsend.yaml or <stage>.yml
uses: fullsend-ai/fullsend/.../reusable-*.yml@latest
with:
fullsend_actions_ref: latest
fullsend_cli_ref: latest
```

Running `fullsend github setup org/repo --upstream-ref main` the template will be rendered
as (excluding other details):

```yaml
# fullsend.yaml or <stage>.yml
uses: fullsend-ai/fullsend/.../reusable-*.yml@main
with:
fullsend_actions_ref: main
fullsend_cli_ref: main
```

Running `fullsend github setup org/repo --upstream-ref v0.15.0` the template will be rendered
as (excluding other details):

```yaml
# fullsend.yaml or <stage>.yml
uses: fullsend-ai/fullsend/.../reusable-*.yml@v0.15.0
with:
fullsend_actions_ref: v0.15.0
fullsend_cli_ref: v0.15.0
```

## Some Future Problems

* Currently images are not versioned, they just have the `latest` tag. This needs to
change so everything moves at the same pace.
* When (and if) we externalize the default agents, in case those have an independent
version which is likely, then the Fullsend version will need to pin to those versions
at the moment of release.
Loading