remove the claude-interactive harness - #804
Conversation
Its only reason to exist was avoiding the metered Agent SDK. That reason is gone twice over: Anthropic paused the metering, and the default claude harness now runs the same binary rather than the SDK. No adopter config selected it. Also adds a nightly task to tend's overlay for restamping the action refs in hand-maintained workflows, which is how the harness went unnoticed on review-reviewers.yaml for three releases. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
tend-agent
left a comment
There was a problem hiding this comment.
The generator collapse (CLAUDE_FAMILY_HARNESSES → harness == "claude") is mechanically equivalent now that KNOWN_HARNESSES == {"claude", "codex"}, the test reparameterization exercises the override harder, and uv run pytest gives 284 passing here. One gap: the harness-count prose cleanup is incomplete, and in two spots the PR left the comment internally inconsistent.
The two files the PR touched now disagree with themselves — the parenthetical was updated but the count word wasn't:
shared/steps/security-preflight.sh—Shared verbatim by all three harness actions (claude/, codex/).— says "three", lists two.shared/steps/validate-claude-auth.sh—Shared by the two Claude harness action (claude/).— "two ... action", now a single Claude action.
And the same drift survives untouched in nine more places:
- "all three harness actions" (now two — claude, codex):
shared/steps/ensure-uv.sh,mark-notification-read.sh,rate-limit-preflight.sh,report-failure.sh, andclaude/action.yaml(so the three harness actions can't drift). - "the two Claude harness actions" (now one):
shared/steps/compose-system-prompt.sh,install-agent-toolchain.sh,install-tend-plugins.sh,restore-sensitive-config.sh,sandbox-setup.sh.
Separately, claude/action.yaml still carries The two Claude actions are swap-in compatible — keep their input surfaces in sync (enforced by the claude-action-input-parity pre-commit hook) — but this PR deletes both the second Claude action and that hook, so the comment now points at two things that no longer exist. Given the PR's premise is retiring prose that had already drifted, this reads as exactly the kind of line worth catching.
These are all outside the diff hunks, so I've left them in the body rather than as inline suggestions. The fix is mechanical (three→two; "the two Claude harness actions"→"the Claude harness action"; drop the input-parity sentence) — happy to push a single sweep commit if you'd like, just say the word.
The deletion left 'all three harness actions' and 'the two Claude harness actions' across shared/steps/, plus a claude/action.yaml comment pointing at the removed second action and its input-parity hook. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Bumps the generator to 0.1.13, syncs the lockfile, and adds the CHANGELOG section the release workflow publishes verbatim as the GitHub Release notes. 13 commits since 0.1.12. The release's substance is the security work: the operational secrets move into a gated `tend` deployment environment, with a secretless review-event relay in `tend-mention` and two new `tend check` checks ([#810](#810)), and `tend check` now verifies the bot cannot bypass the merge restriction ([#795](#795)). Alongside those: the `claude-interactive` harness is removed ([#804](#804)), `tend-review` runs the adopter's `setup:` on the base tree rather than the PR's ([#806](#806)), tend's uv is pinned and isolated from the adopter's ([#807](#807)), and the proxy readiness check waits for the port instead of trusting the CA file ([#811](#811)). Adopters have manual work after this ships: the environment gate is inert until each repo's regenerated workflows name the environment and its secrets are re-minted into it. `TODO.md` carries the per-repo recipe. Once this merges: tag `0.1.13`, which publishes to PyPI and creates the GitHub Release, then regenerate tend's own workflows against the published version. > _This was written by Claude Code on behalf of max-sixty_
Deletes the
claude-interactiveharness, leavingclaudeandcodex. −1152 lines, +86.Why
It was built for one reason: Anthropic's 2026-06-15 change would have metered
claude -pagainst Agent SDK credits while leaving interactive terminal sessions on the subscription, and running the binary under a PTY sidestepped that. That reason is gone twice over. Anthropic paused the change and still lists it paused ("Claude Agent SDK,claude -p, and third-party app usage still draw from your subscription's usage limits"), and the defaultclaudeharness was since rewritten to run the same binary headless rather than going through the SDK at all — so the thing the PTY was avoiding is no longer on either path.Nothing selected it. No adopter config sets
harness:, tend's own dogfooding moved off it at the rollback, and the last caller anywhere wasreview-reviewers.yaml, which had it by accident and was fixed in #803.What it cost to keep: a 667-line parallel composite action, a second smoke workflow, a three-way branch in the generator, a pre-commit hook whose entire job was policing the duplication, and prose across nine files — which had already drifted, since the action's own description still advertised itself as the alternative to
claude-code-action.Restoring it
CLAUDE.mdrecords the removal with a pointer to036f9c4, the last commit containing the harness, so it can be recovered if the metering resumes.Shape of the diff
Deleted —
claude-interactive/action.yaml,.github/workflows/interactive-smoke.yaml, theclaude-action-input-paritypre-commit hook (it existed only to keep the two actions' inputs aligned), fourtest_claude_interactive_*tests,test_claude_interactive_runs_claude_auth_check,test_per_workflow_harness_same_family_no_model_clash, and the now-orphaned regtest snapshot.Collapsed —
CLAUDE_FAMILY_HARNESSESwas a two-element set consulted at six sites acrossconfig.py,checks.py, andworkflows.py. Rather than leave a set of one, the sites now testharness == "claude"directly. Same for the template's{% if cfg.harness in ('claude', 'claude-interactive') %}guards and the "Claude-family" phrasing in adopter-facing comments.Reparameterized —
test_per_workflow_harness_override_targets_only_named_workflowusedclaude-interactiveas its override target. It now overrides tocodex, which exercises the feature harder: the override has to carry its own secret shape, so the test additionally assertsopenai_api_keyappears andclaude_code_oauth_tokendoes not.Also here — a nightly task in tend's
running-tendoverlay for restamping action refs in hand-maintained workflows.initonly rewrites the generatedtend-*.yamlfiles, which is precisely howreview-reviewers.yamlsat on the wrong harness for three releases without anyone noticing.Testing
284 pass (291 before; the 7-test drop is the deleted tests plus one parametrize case). Beyond the suite,
tend init --dry-runwas run for real on both remaining harnesses:claudestampsmax-sixty/tend/claude@0.1.12across all eight workflows,codexstampscodex@0.1.12withopenai_api_key.The gap: no CI run has executed against a workflow generated by this code. The regtests assert the YAML text, not that GitHub accepts it — though the action refs and input names are unchanged for both surviving harnesses, so there's nothing new for GitHub to reject.
If this is wrong
Paused is not cancelled, and Anthropic said it would give notice before shipping a revised version. If the metering returns, this has to be rebuilt or reverted rather than toggled. The bet is that notice plus a commit reference beats carrying a 667-line duplicate that had already started to rot.
No CHANGELOG entry: that section is drafted at release time from the commit range.