Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
f9ac955
refactor(runtime): add Steerer contract for mid-run updates
waynesun09 Sep 3, 2026
4b8e796
refactor(runtime): add RunParams.Steerable and RunMetrics.SessionID
waynesun09 Sep 3, 2026
2e8ace2
refactor(runtime): capture the runtime session id in RunMetrics
waynesun09 Sep 3, 2026
1ecfd0f
feat(runtime): steer a running Claude Code session through a mailbox
waynesun09 Sep 3, 2026
60a25f1
feat(runtime): steer a running codex thread by interrupt and resume
waynesun09 Sep 3, 2026
fd209c4
feat(runtime): steer a running pi session over --mode rpc
waynesun09 Sep 3, 2026
1cad427
docs(runtime): name the steer mailbox and pid file residuals
waynesun09 Sep 3, 2026
913b241
feat(harness): add steer config for the follow-up run watcher
waynesun09 Sep 3, 2026
023ff43
feat(statuscomment): carry a steer marker on the terminal comment
waynesun09 Sep 3, 2026
55142d2
feat(steerwatch): follow-up run watcher with provenance checks
waynesun09 Sep 3, 2026
92f9e3c
feat(run): wire the steer watcher, skip check, and run baseline
waynesun09 Sep 3, 2026
c987823
feat(dispatch)!: gate cancel-in-progress on FULLSEND_STEER and add /f…
waynesun09 Sep 3, 2026
6446aed
feat(cli): add fullsend steer to update a run already in flight
waynesun09 Sep 3, 2026
cbcc822
docs: ADR 0101 and the steer entries in the runtime and harness refer…
waynesun09 Sep 3, 2026
b4796c9
fix(steerwatch): resolve the work item from the forge, not the enviro…
waynesun09 Sep 3, 2026
99e39fd
fix(steerwatch): compare the dispatch chain by path and ref, and floo…
waynesun09 Sep 3, 2026
fdc6840
fix(harness): inherit the steer block through base composition
waynesun09 Sep 3, 2026
fc85f6f
refactor(steerwatch): read run records through the forge adapter
waynesun09 Sep 3, 2026
238fc41
fix(steerwatch): advance the issue baseline only after a delivered steer
waynesun09 Sep 3, 2026
aca7911
fix(steerwatch): build the marker from acknowledged deliveries only
waynesun09 Sep 3, 2026
23d9689
refactor(cli): post the steer comment through the shared forge client
waynesun09 Sep 3, 2026
6c44a21
docs: record the steer surfaces in the contributor references
waynesun09 Sep 3, 2026
a0a6cb7
docs(adr): position 0101 as an extension of ADR 0098
waynesun09 Sep 3, 2026
033a14d
test(cli): compute the steer marker from data, not a test-only export
waynesun09 Sep 3, 2026
83de96b
docs(adr): settle the FULLSEND_STEER gate as interim until ADR 0098 m…
waynesun09 Sep 3, 2026
155fe44
fix(runtime): record a codex steer only once the resume opens the thread
waynesun09 Sep 3, 2026
6ae31be
fix(steerwatch)!: attribute each delta item to its own author
waynesun09 Sep 3, 2026
2c3cc48
fix(steerwatch): withhold the receipt unless the run earned it
waynesun09 Sep 3, 2026
9ee788d
perf(steerwatch): filter the comment listing server-side
waynesun09 Sep 3, 2026
849b08a
fix(runtime): give the codex steer interrupt a longer TERM grace
waynesun09 Sep 3, 2026
18c2a89
fix(runtime): publish the codex thread id mid-stream and split the en…
waynesun09 Sep 3, 2026
b76153a
docs(adr): state the steer text's argv exposure precisely
waynesun09 Sep 3, 2026
739137e
fix(runtime): interrupt a codex turn only when one is actually running
waynesun09 Sep 3, 2026
44bda8c
docs(runtime): align the codex prompt comment with the argv correction
waynesun09 Sep 3, 2026
081c9bd
fix(steerwatch): take amendment authority only from issue_comment runs
waynesun09 Sep 4, 2026
86663e1
fix(statuscomment): scope the steer receipt to the run's own status c…
waynesun09 Sep 4, 2026
04e28a1
docs(adr): treat ADR 0098 as parallel work, not a design this implements
waynesun09 Sep 4, 2026
90071e6
fix(steerwatch): bind an amendment to the comment that authorized it
waynesun09 Sep 4, 2026
16c2c3c
docs(adr): make authenticated receipts a precondition for enabling st…
waynesun09 Sep 4, 2026
bc7c296
docs(adr): document the amendment boundary and correct two authority …
waynesun09 Sep 4, 2026
8bdd5b9
docs: split the gate into preserving the run and steering it
waynesun09 Sep 4, 2026
2de890e
fix(runtime): match a steer echo to its message instead of counting
waynesun09 Sep 4, 2026
87f66f5
fix(cli): decline steering unless the repository preserves runs
waynesun09 Sep 4, 2026
2c60827
fix(scaffold): give this repository's own shim the steer run-name
waynesun09 Sep 4, 2026
3e75416
fix(sticky): strip the trusted marker before neutralizing the history
waynesun09 Sep 4, 2026
a137908
docs: say the receipt check is trusted, and name the default's switch
waynesun09 Sep 4, 2026
c82a30c
fix(runtime): take the steered run's reasoning total instead of summi…
waynesun09 Sep 4, 2026
8b75b99
fix(steerwatch): let the envelope own the steer opening line
waynesun09 Sep 4, 2026
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
12 changes: 12 additions & 0 deletions .github/workflows/fullsend.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@
# stage jobs with -agent- suffix. Roles operate independently (#2452).
name: fullsend

# run-name carries the work item this run is about, which the Actions API
# returns as display_title (ADR 0101). issue_comment and issues runs expose
# no pull_requests[], so without this an in-flight agent run has no
# server-side way to tell a follow-up run on its own work item from one on
# another. For a comment on a PR, github.event.issue.number IS the PR number,
# so the pair covers every event this shim listens for.
#
# This repository's shim is not reached by scaffold sync, so it carries the
# same line as templates/shim-per-repo.yaml by hand;
# TestOwnShimMatchesTemplateRunName keeps the two from drifting.
run-name: ${{ github.repository }}#${{ github.event.issue.number || github.event.pull_request.number }}

on:
issues:
types: [opened, edited, labeled]
Expand Down
97 changes: 97 additions & 0 deletions .github/workflows/reusable-dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,46 @@ jobs:
fi
fi
;;
/fs-steer)
# Steer the run already in flight on this work item
# (ADR 0101). The comment fires the shim like any other
# event; the stage job it selects queues normally and the
# runner's watcher consumes that run as the steer. An
# explicit stage prefix wins, otherwise a PR steers review
# and an issue steers triage. The authorization floor is
# the target stage's own: fix is a mutation stage and
# keeps its write floor, so `fix:` cannot be used to
# reach fix from a triage-level account.
STEER_TARGET="$(printf '%s\n' "${COMMENT_BODY}" | head -1 | tr -d '\r' | awk '{print $2}')"
case "${STEER_TARGET}" in
review:) STEER_STAGE="review" ;;
fix:) STEER_STAGE="fix" ;;
triage:) STEER_STAGE="triage" ;;
*)
if [[ "${ISSUE_IS_PR}" == "true" ]]; then
STEER_STAGE="review"
else
STEER_STAGE="triage"
fi
;;
esac
if [[ "${STEER_STAGE}" == "fix" && "${ISSUE_IS_PR}" != "true" ]]; then
STEER_STAGE=""
fi
if [[ "${STEER_STAGE}" == "review" && "${ISSUE_IS_PR}" != "true" ]]; then
STEER_STAGE=""
fi
if [[ -n "${STEER_STAGE}" && "${COMMENT_USER_TYPE}" != "Bot" ]]; then
if [[ "${STEER_STAGE}" == "fix" ]]; then
if is_authorized; then
STAGE="fix"
TRIGGER_SOURCE="${COMMENT_USER_LOGIN}"
fi
elif is_authorized triage; then
STAGE="${STEER_STAGE}"
fi
fi
;;
/fs-retro)
if [[ "${COMMENT_USER_TYPE}" != "Bot" ]] && is_authorized; then
STAGE="retro"
Expand Down Expand Up @@ -611,6 +651,12 @@ jobs:
needs: route
if: needs.route.outputs.stage == 'triage'
runs-on: ${{ inputs.runner_image }}
# Every stage job below carries the same cancel-in-progress expression.
# Unset, or anything but "true", is today's behaviour: a newer event on
# the same work item cancels the run in flight. Set to "true" in a
# consumer repository, the run in flight instead absorbs the update
# through the runner's follow-up run watcher, and the newer event waits
# as the single pending run `queue: single` allows (ADR 0101).
concurrency:
group: fullsend-triage-${{ github.repository }}-${{ github.event.issue.number || github.event.pull_request.number }}
cancel-in-progress: ${{ vars.FULLSEND_PRESERVE_RUNS != 'true' }}
Expand Down Expand Up @@ -704,6 +750,12 @@ jobs:
FULLSEND_OPENAI_AUDIENCE: ${{ vars.FULLSEND_OPENAI_AUDIENCE }}
FULLSEND_OPENAI_IDENTITY_PROVIDER_ID: ${{ vars.FULLSEND_OPENAI_IDENTITY_PROVIDER_ID }}
FULLSEND_OPENAI_SERVICE_ACCOUNT_ID: ${{ vars.FULLSEND_OPENAI_SERVICE_ACCOUNT_ID }}
# The steering runner declines unless this is "true": a run that is
# about to be cancelled cannot usefully be steered, and steering one
# that will be cancelled anyway is the mixed state ADR 0101 calls
# worse than today. `vars` is not otherwise visible to the runner —
# FULLSEND_REPO_VARS reaches the sandbox env, not this process.
FULLSEND_PRESERVE_RUNS: ${{ vars.FULLSEND_PRESERVE_RUNS }}
with:
agent: triage
fullsend-dir: ${{ inputs.install_mode == 'per-repo' && '.fullsend' || '' }}
Expand Down Expand Up @@ -843,6 +895,12 @@ jobs:
FULLSEND_OPENAI_AUDIENCE: ${{ vars.FULLSEND_OPENAI_AUDIENCE }}
FULLSEND_OPENAI_IDENTITY_PROVIDER_ID: ${{ vars.FULLSEND_OPENAI_IDENTITY_PROVIDER_ID }}
FULLSEND_OPENAI_SERVICE_ACCOUNT_ID: ${{ vars.FULLSEND_OPENAI_SERVICE_ACCOUNT_ID }}
# The steering runner declines unless this is "true": a run that is
# about to be cancelled cannot usefully be steered, and steering one
# that will be cancelled anyway is the mixed state ADR 0101 calls
# worse than today. `vars` is not otherwise visible to the runner —
# FULLSEND_REPO_VARS reaches the sandbox env, not this process.
FULLSEND_PRESERVE_RUNS: ${{ vars.FULLSEND_PRESERVE_RUNS }}
with:
agent: code
fullsend-dir: ${{ inputs.install_mode == 'per-repo' && '.fullsend' || '' }}
Expand Down Expand Up @@ -971,6 +1029,12 @@ jobs:
FULLSEND_OPENAI_AUDIENCE: ${{ vars.FULLSEND_OPENAI_AUDIENCE }}
FULLSEND_OPENAI_IDENTITY_PROVIDER_ID: ${{ vars.FULLSEND_OPENAI_IDENTITY_PROVIDER_ID }}
FULLSEND_OPENAI_SERVICE_ACCOUNT_ID: ${{ vars.FULLSEND_OPENAI_SERVICE_ACCOUNT_ID }}
# The steering runner declines unless this is "true": a run that is
# about to be cancelled cannot usefully be steered, and steering one
# that will be cancelled anyway is the mixed state ADR 0101 calls
# worse than today. `vars` is not otherwise visible to the runner —
# FULLSEND_REPO_VARS reaches the sandbox env, not this process.
FULLSEND_PRESERVE_RUNS: ${{ vars.FULLSEND_PRESERVE_RUNS }}
with:
agent: review
fullsend-dir: ${{ inputs.install_mode == 'per-repo' && '.fullsend' || '' }}
Expand Down Expand Up @@ -1123,7 +1187,16 @@ jobs:
if [[ ! "${TRIGGER_SOURCE}" =~ \[bot\]$ ]]; then
COMMENT_BODY="$(echo "${EVENT_PAYLOAD}" | jq -r '.comment.body // empty')"
if [[ -n "${COMMENT_BODY}" ]]; then
# Strip whichever slash command carried the instruction. A
# /fs-steer comment routed here (ADR 0101) would otherwise
# keep "/fs-steer" (and an optional "fix:" target) as the
# first words of the instruction.
INSTRUCTION="${COMMENT_BODY#/fs-fix}"
if [[ "${INSTRUCTION}" == "${COMMENT_BODY}" ]]; then
INSTRUCTION="${COMMENT_BODY#/fs-steer}"
INSTRUCTION="${INSTRUCTION#"${INSTRUCTION%%[![:space:]]*}"}"
INSTRUCTION="${INSTRUCTION#fix:}"
fi
INSTRUCTION="$(printf '%s\n' "${INSTRUCTION}" | sed 's/^[.,;:!?]*//')"
INSTRUCTION="${INSTRUCTION#"${INSTRUCTION%%[![:space:]]*}"}"
fi
Expand Down Expand Up @@ -1251,6 +1324,12 @@ jobs:
FULLSEND_OPENAI_AUDIENCE: ${{ vars.FULLSEND_OPENAI_AUDIENCE }}
FULLSEND_OPENAI_IDENTITY_PROVIDER_ID: ${{ vars.FULLSEND_OPENAI_IDENTITY_PROVIDER_ID }}
FULLSEND_OPENAI_SERVICE_ACCOUNT_ID: ${{ vars.FULLSEND_OPENAI_SERVICE_ACCOUNT_ID }}
# The steering runner declines unless this is "true": a run that is
# about to be cancelled cannot usefully be steered, and steering one
# that will be cancelled anyway is the mixed state ADR 0101 calls
# worse than today. `vars` is not otherwise visible to the runner —
# FULLSEND_REPO_VARS reaches the sandbox env, not this process.
FULLSEND_PRESERVE_RUNS: ${{ vars.FULLSEND_PRESERVE_RUNS }}
with:
agent: fix
fullsend-dir: ${{ inputs.install_mode == 'per-repo' && '.fullsend' || '' }}
Expand Down Expand Up @@ -1361,6 +1440,12 @@ jobs:
FULLSEND_OPENAI_AUDIENCE: ${{ vars.FULLSEND_OPENAI_AUDIENCE }}
FULLSEND_OPENAI_IDENTITY_PROVIDER_ID: ${{ vars.FULLSEND_OPENAI_IDENTITY_PROVIDER_ID }}
FULLSEND_OPENAI_SERVICE_ACCOUNT_ID: ${{ vars.FULLSEND_OPENAI_SERVICE_ACCOUNT_ID }}
# The steering runner declines unless this is "true": a run that is
# about to be cancelled cannot usefully be steered, and steering one
# that will be cancelled anyway is the mixed state ADR 0101 calls
# worse than today. `vars` is not otherwise visible to the runner —
# FULLSEND_REPO_VARS reaches the sandbox env, not this process.
FULLSEND_PRESERVE_RUNS: ${{ vars.FULLSEND_PRESERVE_RUNS }}
with:
agent: retro
fullsend-dir: ${{ inputs.install_mode == 'per-repo' && '.fullsend' || '' }}
Expand Down Expand Up @@ -1457,6 +1542,12 @@ jobs:
FULLSEND_OPENAI_AUDIENCE: ${{ vars.FULLSEND_OPENAI_AUDIENCE }}
FULLSEND_OPENAI_IDENTITY_PROVIDER_ID: ${{ vars.FULLSEND_OPENAI_IDENTITY_PROVIDER_ID }}
FULLSEND_OPENAI_SERVICE_ACCOUNT_ID: ${{ vars.FULLSEND_OPENAI_SERVICE_ACCOUNT_ID }}
# The steering runner declines unless this is "true": a run that is
# about to be cancelled cannot usefully be steered, and steering one
# that will be cancelled anyway is the mixed state ADR 0101 calls
# worse than today. `vars` is not otherwise visible to the runner —
# FULLSEND_REPO_VARS reaches the sandbox env, not this process.
FULLSEND_PRESERVE_RUNS: ${{ vars.FULLSEND_PRESERVE_RUNS }}
with:
agent: prioritize
fullsend-dir: ${{ inputs.install_mode == 'per-repo' && '.fullsend' || '' }}
Expand Down Expand Up @@ -1821,6 +1912,12 @@ jobs:
JIRA_TOKEN: ${{ secrets.JIRA_TOKEN }}
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
JIRA_BASE_URL: ${{ inputs.jira_base_url || vars.JIRA_BASE_URL }}
# The steering runner declines unless this is "true": a run that is
# about to be cancelled cannot usefully be steered, and steering one
# that will be cancelled anyway is the mixed state ADR 0101 calls
# worse than today. `vars` is not otherwise visible to the runner —
# FULLSEND_REPO_VARS reaches the sandbox env, not this process.
FULLSEND_PRESERVE_RUNS: ${{ vars.FULLSEND_PRESERVE_RUNS }}
with:
agent: ${{ matrix.agent }}
version: ${{ inputs.fullsend_version || job.workflow_sha }}
Expand Down
Loading
Loading