Skip to content
Merged
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
9 changes: 9 additions & 0 deletions .github/workflows/go-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ on:
- "scripts/test-tmux-compat-prefix.sh"
- "scripts/test-tmux-compatibility.sh"
- "scripts/tmux-compat-lib.sh"
- ".github/workflows/herdr-sync.yml"
- "scripts/herdr-staleness.sh"
- "scripts/test-herdr-staleness.sh"
# Bundled integration assets are shipped JavaScript that the Go suite
# drives under node. A change to one of them changes what Sidecar
# installs into a user's agent, and without this it triggered no CI run
Expand Down Expand Up @@ -49,6 +52,9 @@ on:
- "scripts/test-tmux-compat-prefix.sh"
- "scripts/test-tmux-compatibility.sh"
- "scripts/tmux-compat-lib.sh"
- ".github/workflows/herdr-sync.yml"
- "scripts/herdr-staleness.sh"
- "scripts/test-herdr-staleness.sh"
- "internal/agentintegration/assets/**"
- "internal/agentactivity/manifests/**"
- "internal/agentintegration/upstream/**"
Expand Down Expand Up @@ -85,6 +91,9 @@ jobs:
with:
node-version: "24"

- name: Herdr staleness workflow regression
run: ./scripts/test-herdr-staleness.sh

- name: Test
run: go test ./...
env:
Expand Down
88 changes: 66 additions & 22 deletions .github/workflows/herdr-sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ jobs:
permissions:
contents: write
pull-requests: write
statuses: write
outputs:
changed: ${{ steps.diff.outputs.changed }}
ref: ${{ steps.diff.outputs.ref }}
ref: ${{ steps.push.outputs.ref || steps.diff.outputs.ref }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SYNC_BRANCH: bot/herdr-sync
Expand Down Expand Up @@ -95,7 +96,7 @@ jobs:

if [ -n "$files" ] || [ "$locks_moved" = true ]; then
changed=true
ref="$SYNC_BRANCH"
ref=""
else
changed=false
ref="$GITHUB_SHA"
Expand Down Expand Up @@ -152,6 +153,7 @@ jobs:
# current sync output. Re-running updates the existing review in place
# rather than opening a second one.
- name: Push the sync branch
id: push
if: steps.diff.outputs.changed == 'true'
run: |
set -euo pipefail
Expand All @@ -172,6 +174,26 @@ jobs:
git commit -m "chore(herdr): sync detection manifests to $tag" \
-m "Vendored from herdr $ref by go run ./internal/tools/herdrsync."
git push --force origin "$SYNC_BRANCH"
echo "ref=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"

- name: Publish checks on the proposed commit
if: steps.push.outputs.ref != ''
env:
SYNC_SHA: ${{ steps.push.outputs.ref }}
CHECKS_OUTCOME: ${{ steps.checks.outcome }}
LINT_OUTCOME: ${{ steps.lint.outcome }}
run: |
set -euo pipefail
state=failure
if [ "$CHECKS_OUTCOME" = success ] && [ "$LINT_OUTCOME" = success ]; then state=success; fi
gh api --method POST "repos/$GITHUB_REPOSITORY/statuses/$SYNC_SHA" \
-f state="$state" -f context="Herdr sync / Go checks" \
-f description="Build, tests, and lint for the proposed sync" \
-f target_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"
gh api --method POST "repos/$GITHUB_REPOSITORY/statuses/$SYNC_SHA" \
-f state=pending -f context="Herdr sync / differential" \
-f description="Waiting for both differential modes" \
-f target_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"

- name: Open or update the review
if: steps.diff.outputs.changed == 'true'
Expand All @@ -195,6 +217,8 @@ jobs:
echo "> \`go build ./...\`, \`go test ./...\` and golangci-lint passed on this tree in the [run]($run_url) that produced it. A pull request opened with \`GITHUB_TOKEN\` does not trigger \`pull_request\` workflows, so Go CI posts no separate check here."
fi
echo
echo "The commit statuses on this pull request report Go checks and both differential modes. Wait for both to pass before merging."
echo
cat internal/agentactivity/manifests/report.md
echo
echo "---"
Expand All @@ -219,21 +243,23 @@ jobs:

differential:
name: Differential harness against the pinned Herdr release
# Runs on the sync branch when there is one, so the harness judges the
# manifests the review actually proposes; on the workflow's own commit
# otherwise. !cancelled() rather than success() because a sync that failed
# its Go suite still pushed a branch worth judging.
# Judge only the exact successfully published commit, or the workflow
# commit when nothing changed. An import/push failure publishes no ref;
# never fall back to a stale bot branch and report that as fresh evidence.
needs: sync
if: ${{ !cancelled() }}
if: ${{ !cancelled() && needs.sync.outputs.ref != '' }}
runs-on: ubuntu-latest
permissions:
contents: read
statuses: write
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HERDR_REPO: herdrdev/herdr
steps:
- name: Checkout
uses: actions/checkout@v7
with:
ref: ${{ needs.sync.outputs.ref || github.sha }}
ref: ${{ needs.sync.outputs.ref }}

- name: Set up Go
uses: actions/setup-go@v7
Expand Down Expand Up @@ -294,6 +320,20 @@ jobs:
} >> "$GITHUB_STEP_SUMMARY"
done

- name: Publish differential status on the proposed commit
if: always() && needs.sync.outputs.changed == 'true'
env:
SYNC_SHA: ${{ needs.sync.outputs.ref }}
RESULT: ${{ job.status }}
run: |
set -euo pipefail
state=failure
if [ "$RESULT" = success ]; then state=success; fi
gh api --method POST "repos/$GITHUB_REPOSITORY/statuses/$SYNC_SHA" \
-f state="$state" -f context="Herdr sync / differential" \
-f description="Both differential modes: $RESULT" \
-f target_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"

staleness:
name: Staleness of the committed lock
# Deliberately after sync and deliberately not conditional on it passing.
Expand Down Expand Up @@ -330,18 +370,13 @@ jobs:
run: |
set -euo pipefail
out=$(mktemp -d)
args=(-out "$out")
# The integration-asset half of the sync writes to a second root.
# Redirect that to a throwaway directory too when the tool has the
# flag, so this run cannot write into the checkout at all; asking the
# tool's own usage keeps this correct either side of that landing.
if go run ./internal/tools/herdrsync -h 2>&1 | grep -q -- '-integration-out'; then
args+=(-integration-out "$(mktemp -d)")
fi
args=(-out "$out" -integration-out "$(mktemp -d)")
echo "HERDR_FRESH_LOCK=$out/upstream.lock.json" >> "$GITHUB_ENV"
go run ./internal/tools/herdrsync "${args[@]}" > /dev/null

- name: Compare against the committed lock
env:
BASE_BRANCH: ${{ github.event.repository.default_branch }}
run: |
set -euo pipefail
stale=$(./scripts/herdr-staleness.sh \
Expand All @@ -355,7 +390,7 @@ jobs:
exit 0
fi

open=$(gh pr list --head "$SYNC_BRANCH" --state open --json number --jq '.[0].number // empty')
review=$(gh pr list --head "$SYNC_BRANCH" --base "$BASE_BRANCH" --state open --json number,headRefOid --jq '.[0] // empty')
{
echo "### Stale vendored manifests"
echo
Expand All @@ -364,13 +399,22 @@ jobs:
echo '```'
} >> "$GITHUB_STEP_SUMMARY"

if [ -n "$open" ]; then
echo "$stale"
echo "sync pull request #$open is open and carries these bumps; not stale"
exit 0
if [ -n "$review" ]; then
number=$(jq -r .number <<< "$review")
sha=$(jq -r .headRefOid <<< "$review")
proposed="$RUNNER_TEMP/proposed-herdr-lock.json"
gh api "repos/$GITHUB_REPOSITORY/contents/internal/agentactivity/manifests/upstream.lock.json?ref=$sha" \
--jq .content | base64 --decode > "$proposed"
missing=$(./scripts/herdr-staleness.sh "$HERDR_FRESH_LOCK" "$proposed" "$MAX_AGE_DAYS")
if [ -z "$missing" ]; then
echo "sync pull request #$number actually carries the stale bumps; awaiting review"
exit 0
fi
echo "Open sync pull request #$number does not carry these stale bumps:" >&2
echo "$missing" >&2
fi

echo "$stale" >&2
echo >&2
echo "upstream has been ahead of the committed lock for more than $MAX_AGE_DAYS days with no open $SYNC_BRANCH pull request, so the sync is not landing; run scripts/sync-herdr.sh and read the report" >&2
echo "upstream has been ahead of the committed lock for more than $MAX_AGE_DAYS days without a $SYNC_BRANCH pull request carrying the bumps, so the sync is not landing; run scripts/sync-herdr.sh and read the report" >&2
exit 1
15 changes: 15 additions & 0 deletions docs/guides/active/herdr-sync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Maintaining the Herdr sync

The weekly `Herdr sync` GitHub Actions workflow imports detection manifests, alias and authority metadata, and integration source assets from Herdr's default branch. It pins a released Herdr binary separately for differential verification. Run it manually with `gh workflow run herdr-sync.yml`; reproduce the import with `scripts/sync-herdr.sh`.

The workflow opens or updates `bot/herdr-sync`. Its Go checks and both differential modes are posted as commit statuses on the exact published commit. An import or push failure does not validate an older sync branch. A failed check leaves the proposed changes available for review with a failing status. Merge only when both statuses pass.

Staleness compares current upstream versions with the committed lock. An open sync PR exempts a stale bump only when its own pinned lock actually contains that bump. An old PR does not hide newer missing rules.

The importer accepts the legacy authority table and the current integration/notes table in Herdr's agent documentation. Unknown table schemas, agent names, or note meanings fail before vendoring. Native self-reporting is recorded separately from installable lifecycle integrations. Imported authority metadata never grants a Sidecar integration tier; ported assets require their own proof.

A sync can require changes to overlays or the engine. Remove a disable when upstream removes its target. Retire regex rewrites when upstream removes the rule, and replace obsolete synthetic fixtures with current upstream shapes. The Codex no-match fallback is `unknown` (`codex_state_ambiguous`), including through Sidecar's live detection path; lack of working evidence cannot announce completion. Explicit matched rules still determine their declared state.

Validation: `GOWORK=off SIDECAR_REQUIRE_NODE=1 go test ./...`, `GOWORK=off go build ./...`, and `GOWORK=off golangci-lint run ./...`. With the pinned binary available, run `HERDR_BIN=/path/to/herdr scripts/herdr-diff.sh` and the same command with `--merged`. The default comparison permits named Sidecar overlay differences; merged mode must agree on every compared fixture.

Vendoring a new agent does not register it as a Sidecar provider or install its hooks. Letta's source assets and manifest are available for a later deliberate port; existing integration ports remain independently versioned.
2 changes: 1 addition & 1 deletion internal/agentactivity/activity.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ func identifyProcessName(command string) string {
//
// None of them needs the versioned-binary prefix rule: `muse` is the only
// entry in the extracted versioned_binary_prefixes table.
case name == "cline":
case oneOf(name, "cline", ".cline"):
return "cline"
case oneOf(name, "devin", "devin cli", "devin-cli"):
return "devin"
Expand Down
Loading
Loading