README.md

June 18, 2026 · View on GitHub

tend logoTend

PyPI License: MIT CI maintained with tend

Tend allows open-source projects to have an agent as a dutiful junior maintainer. The agent can review PRs, triage issues, fix CI, help out with research, maintain a changelog, sweep the repo for improvements, refine documentation, etc.

Current status: Tend is in its early days. It has been working extremely well in Worktrunk for the past couple of months, such that folks suggested I generalize it into its own project.

Structure

To use Tend, a project needs:

  • A GitHub account for the agent (for example this project's is @tend-agent)
  • One of:
    • A Claude Max subscription (harness = "claude")
    • An OpenAI API key (harness = "codex"). A ChatGPT subscription via a Codex auth.json is not compatible with tend's concurrent workflows — see Codex (alternative).

Tend offers the default code & guidance for the agent. Specifically that means:

  • A set of workflow templates
  • A very particular set of Skills
    • ...skills it has acquired over a very long career (two months)

Each project's agent remains completely under its control, and runs only in the project's Github Actions environment. The Tend project never sees any tokens / keys / etc.

Quick start

The easiest way to get started is to install the Tend plugin into a local Claude Code session, and run the /install-tend skill:

claude plugin marketplace add max-sixty/tend
claude plugin install install-tend@tend
claude /install-tend

It'll take 5-15 minutes to set up the config, workflow generation, bot account, secrets, and branch protection. Tend is configured through a config file and a repo-local /running-tend skill.

Reasons not to use Tend

  • Tend uses lots of tokens. A Claude subscription, an Anthropic API key, an OpenAI API key, or a ChatGPT plan is needed to fund the runs.
  • While it's built to protect important secrets, a determined attacker can get a) the bot's token and b) the harness auth credential (Claude OAuth token, OpenAI API key, or ChatGPT auth.json). They can't do that much with these: burn some tokens and close some issues.
    • They specifically cannot merge to the default branch, nor create releases.

Workflows

WorkflowTriggerWhat happens
reviewPR opened/updatedReviews for correctness and duplication. Traces error paths. Monitors CI. Pushes fixes to bot-authored PRs.
mention@bot mention, reviewResponds to requests in PR and issue conversations.
triageIssue openedClassifies the issue, checks for duplicates, reproduces bugs, attempts conservative fixes.
ci-fixCI fails on default branchReads failure logs, identifies root cause, searches for the same pattern elsewhere, opens a fix PR.
nightlyDailyResolves conflicts on open PRs, reviews recent commits, surveys ~10 files for bugs and stale docs, closes resolved issues, regenerates tend workflow files.
weeklyWeeklyReviews dependency PRs, approves safe patch and minor updates (the bot never merges — a merge restriction is the security boundary).
notificationsEvery 15 minutesPolls GitHub notifications, responds to unhandled mentions, marks handled threads as read.
review-runsDailyReviews recent CI runs for behavioral problems and proposes skill/config improvements.

Scheduled workflows also support manual dispatch for testing. All are enabled by default except ci-fix, which requires watched_workflows to be configured. Any can be disabled:

workflows:
  weekly:
    enabled: false

How it works

uvx tend@latest init reads .config/tend.yaml and writes tend-*.yaml workflow files into .github/workflows/. Each workflow handles triggers, skip conditions, concurrency, and permissions — then calls the composite action for the configured harness, pinned to the released generator version (max-sixty/tend@X.Y.Z for Claude, max-sixty/tend/codex@X.Y.Z for Codex). The nightly regen restamps a newer tag when a new tend version ships.

Both actions run the same security and rate-limit preflight checks and resolve bot identity. They differ in how the agent runs:

  • Claude harness — runs the official claude binary headless (claude -p) as a non-sudo sandbox user behind a local credential-injecting proxy, so the bot token and Anthropic credential never enter the agent's environment. Each workflow's prompt is a slash command (/tend-ci-runner:review) that loads the matching skill.
  • Codex harness — installs the @openai/codex CLI on the runner and shells out to codex exec. An AGENTS.md staged into $CODEX_HOME teaches Codex to resolve /tend-ci-runner:NAME references to the bundled skill markdown.

Edit the config or the generator — not the workflow files. They're regenerated on every tend@latest init.

Security

Tend gives Claude write access to a repository. The security model has five layers:

Merge restriction is the primary boundary. A GitHub ruleset prevents the bot from merging to protected branches — bot-authored PRs require human approval. tend check verifies this; tend check --fix creates the ruleset.

Credential isolation — the Claude harness runs the agent as a separate non-sudo user and keeps the bot token and Anthropic credential in a local proxy that injects them per host. The agent holds only dummies, so code running in the session can't read the real secrets. The Codex harness passes them directly.

Config pinning — the action restores .claude/, .mcp.json, .claude.json, .gitmodules, .ripgreprc, and CLAUDE.md from the base branch before the agent starts, blocking both startup-time code execution and prompt injection from a PR's own copy of those files.

Rate limiting — Burst detection (10 PRs and 10 issues per 20 minutes, checked independently) and daily spike detection halt the bot before runaway loops cause damage.

Fixed prompts — Workflow prompts come from the action, not from attacker-controlled input like PR descriptions or comments.

Full threat model: docs/security-model.md.

Configuration

.config/tend.yaml — only bot_name is required. The default harness runs Claude; harness: codex selects OpenAI Codex (see Harnesses below).1

bot_name: my-project-bot

# Optional — defaults to "claude"
# harness: codex
# effort: medium   # codex only: low | medium | high | xhigh

Repo secrets depend on the harness:

HarnessRequired secrets
claudeTEND_BOT_TOKEN + one of CLAUDE_CODE_OAUTH_TOKEN (subscription) or ANTHROPIC_API_KEY (API-billed)
codexTEND_BOT_TOKEN + OPENAI_API_KEY (pay-per-token).

TEND_BOT_TOKEN is the bot account's PAT — see example config for scopes. CLAUDE_CODE_OAUTH_TOKEN is from claude setup-token. The other two are standard API keys from console.anthropic.com and platform.openai.com. See Codex (alternative) for why the Codex subscription auth.json path isn't supported; docs/security-model.md has the full leak breakdown.

All other options — secret name overrides, setup steps, protected branches, workflow overrides, schedules — are documented in docs/tend.example.yaml.

Project context

Tend reads CLAUDE.md like any Claude Code session — build commands, test commands, project conventions all go there.

For tend-specific guidance, add a skill overlay at .claude/skills/running-tend/SKILL.md. Common uses: recording which CI workflow names tend-ci-fix watches, PR title conventions, label policies.

Harnesses

Tend supports two harnesses. Pick whichever fits the credentials and billing path that already work for you; both run the same workflows and skills.1

Claude (default)

Runs the official claude binary headless (claude -p) as a non-sudo sandbox user behind a local credential-injecting proxy: the bot token and the Anthropic credential live only in the proxy, never in the agent's environment. Two auth modes:

  • CLAUDE_CODE_OAUTH_TOKEN (recommended with a Claude subscription) — Claude Code OAuth token from claude setup-token, funded by the subscription's usage limits.
  • ANTHROPIC_API_KEY — standard API key from console.anthropic.com, billed per token against the Console org. Pick this when there's no Claude subscription, when the bot should bill against a dedicated Console org, or when per-key revocation matters.

The proxy injects whichever you set into requests to api.anthropic.com; the agent itself only ever holds a dummy.

Codex (alternative)

Installs @openai/codex on the runner and invokes codex exec against a bundled AGENTS.md that teaches it to resolve tend's slash commands to skill markdown.

Use OPENAI_API_KEY (a standard OpenAI API key, pay-per-token, from platform.openai.com). Works for any repo, public or private.

Subscription auth.json is not supported. Codex rotates that refresh token on every API call and invalidates the prior token; tend runs multiple workflows concurrently (review, mention, triage, nightly, …), so each call would invalidate the credential the other in-flight jobs are using. A scheduled refresher works around the ~8-day rotation but not the per-call invalidation between concurrent jobs. Use OPENAI_API_KEY instead.

Badge

A badge signals the repo is maintained with tend:

[![maintained with tend](https://img.shields.io/badge/maintained_with-tend-bba580?logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwxNikgc2NhbGUoMC4wMTI1LC0wLjAxMjUpIiBmaWxsPSIjZmZmIiBzdHJva2U9Im5vbmUiPjxwYXRoIGQ9Ik02ODAgMTEyOCBjNjIgLTk2IDY5IC0xNzggMjAgLTI0MSAtMTcgLTIyIC0yMCAtNDAgLTIwIC0xMzQgbDEgLTEwOCAyMSAyOCBjMTEgMTYgMzAgNDcgNDIgNzAgMTIgMjIgMzIgNDkgNDYgNTkgMzcgMjcgMTE0IDM4IDE4NCAyNyA5MyAtMTUgOTQgLTE4IDQ0IC03OSAtNzIgLTg4IC0xMDkgLTExMyAtMTc2IC0xMTcgLTMxIC0yIC02NCAxIC03MiA2IC0yMyAxNSAyMSA1NiAxMDcgOTggNDAgMjAgNzEgMzggNjkgNDAgLTYgNyAtODggLTE3IC0xMjYgLTM3IC00OSAtMjUgLTEwMCAtNzggLTEyMSAtMTI1IC0xNSAtMzMgLTE5IC02NiAtMTkgLTE4OCAwIC0xNTcgOCAtMTk1IDUwIC0yMzIgMTcgLTE2IDM2IC0yMCA4NSAtMTkgNjIgMSA2MyAxIDczIC0zMiA5IC0zMiA5IC0zMyAtMjIgLTQwIC01MCAtMTIgLTEzMiAtNyAtMTY0IDEwIC00MCAyMSAtNzkgNjkgLTkyIDExNCAtNSAyMCAtMTAgMTAyIC0xMCAxODIgMCA4MCAtNSAxNjIgLTExIDE4NCAtMjIgNzkgLTEzNSAxNjYgLTIzNCAxODEgLTM3IDYgLTM1IDMgMzAgLTI4IDc4IC0zOSAxNDQgLTkxIDEzMiAtMTA0IC01IC00IC0zNyAtOCAtNzEgLTggLTc3IDAgLTExNyAyNCAtMTgyIDEwOSAtNTIgNjggLTUxIDcwIDQyIDg1IDcxIDExIDE0MyAwIDE4MyAtMjkgMTYgLTExIDQwIC00MyA1NCAtNzMgMTMgLTI5IDMyIC01OSA0MSAtNjYgMTQgLTEyIDE2IC03IDE2IDU4IDAgNTkgNCA3NyAyMyAxMDIgMTkgMjYgMjMgNDYgMjUgMTMwIDMgNjcgMCA5OSAtNyA5OSAtNyAwIC0xMSAtMjMgLTEyIC01NyAwIC0zMiAtNiAtNzYgLTEyIC05NyBsLTEyIC00MCAtMjcgMzIgYy0zNCA0MSAtNDMgOTYgLTI0IDE1MSAxNCA0MSA3NSAxNDEgODYgMTQxIDMgMCAyMSAtMjQgNDAgLTUyeiIvPjwvZz48L3N2Zz4K)](https://github.com/max-sixty/tend)

The install-tend skill offers to add this automatically during setup.

License

MIT

Footnotes

  1. A third harness, claude-interactive, runs the same claude binary under a PTY supervisor (script(1) with a Stop-hook sentinel) instead of headless -p. Same proxy isolation and auth as the default Claude harness. Opt in with harness: claude-interactive. 2