> ## Documentation Index
> Fetch the complete documentation index at: https://docs.auto.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Self-Improvement

> An agent that sweeps the project's own session history and PR feedback on a schedule, then proposes concrete improvements to the app and to the .auto/ configuration itself.

The self-improvement example closes the loop in "improved by itself": an agent that periodically studies the factory's own output — session transcripts, tool-call failures, dropped triggers, PR review feedback — and turns what it finds into concrete, evidenced proposals. Its findings target the application *or* the `.auto/` directory itself: a prompt that keeps producing the same review nit, a trigger whose `where` filter silently drops real events, a preference a human has now stated twice. Because `.auto/` is just YAML in the repository, every accepted proposal becomes a normal pull request that [GitHub Sync](/concepts/github-sync) plans and applies — the factory reconfigures itself through the same door humans use.

## How it works

1. **A heartbeat spawns a sweep.** Every two hours a cron trigger spawns a fresh session (no live-session bookkeeping needed — each sweep is standalone).
2. **The agent reads its own project.** Through the read-only `auto.sessions.*` introspection tools it triages recent sessions, greps transcripts for repeated failures, and inspects which triggers fired and which were dropped. Through brokered GitHub tools it reads recent PRs: review comments, expressed preferences, repeated friction, CI failures.
3. **It diagnoses, bounded.** At most three deep-dives per sweep; every finding must cite its evidence (a tool call, an event, a PR comment, a prompt line) and name the concrete surface to change.
4. **It stays stateful without storing state.** Each sweep begins by finding the *previous* sweep's report with `auto.sessions.list` and reading its final message — so resolved problems get closures, recurring ones get escalated, and nothing is re-announced.
5. **It reports where the team lives.** Actionable findings land in Slack `#dev` as one short top-level line plus one threaded detail reply. Quiet sweeps post nothing.

## The configuration

Two files. The repository mount is deliberately **read-only** — `contents: read` means there is no push credential, so the agent's writes are limited to Slack messages by construction. The mount also provisions the brokered GitHub tools: a `kind: github` tool only works for sessions that hold at least one `githubApp` mount.

```yaml .auto/fragments/environments/agent-runtime.yaml theme={null}
harness: claude-code
environment:
  name: agent-runtime
  image:
    kind: preset
    name: node24
  resources:
    memoryMB: 8192
```

```yaml .auto/agents/self-improvement.yaml theme={null}
name: self-improvement
model:
  provider: anthropic
  id: claude-opus-4-8
identity:
  displayName: Self Improvement
  username: self-improvement
  avatar:
    asset: .auto/assets/self-improvement.png
  description: Reviews PR feedback, read-only data, and Auto sessions to propose concrete improvements.
imports:
  - ../fragments/environments/agent-runtime.yaml
systemPrompt: |
  You are the self-improvement agent for acme/widgets and its Auto project.
  Review real evidence and propose high-leverage improvements to the
  application or to its Auto agents, prompts, triggers, and processes.

  Evidence sources:
  - Auto sessions: status, timing, conversations, tool calls, triggers, and
    transcript search.
  - GitHub PRs: review comments, expressed preferences, repeated friction,
    unresolved blockers, and CI failures.
  - Connected read-only MCP tools: logs, metrics, traces, incidents, support,
    analytics, and docs. Do not mutate external systems from this workflow.

  Diagnosis standards:
  - Evidence before verdicts: cite the relevant tool call, event, PR comment,
    log pattern, or prompt text.
  - Prefer high-confidence, high-leverage fixes, especially changes the user
    wants and that can be automated going forward.
  - A preference need not be repeated before you suggest encoding it; repetition
    only raises confidence and priority.
  - Every finding names a concrete app, test, doc, agent, trigger, prompt, or
    process change.
  - Your own agent's past sessions are in scope - scrutinize them like any
    other session.

  Report format (your final message, every sweep):
  1. Verdict - one line: top opportunity, closures, or why more data is needed.
  2. Findings - each with evidence, affected surface, and the proposed fix.
  3. Closures - previously reported problems now resolved.
  4. Deferred - promising leads skipped because they need more evidence.

  Slack protocol (#dev): post only when there is something actionable. One
  short top-level line (sweep time and counts), then exactly one threaded
  reply with the detail as mrkdwn bullets. Use the threadId returned by
  chat.send for the reply; never guess thread ids. Links are
  <https://url|text>.
initialPrompt: |
  A scheduled heartbeat spawned this session (scheduled at
  "{{heartbeat.scheduledAt}}") to sweep the project's recent sessions
  for failures, anomalies, PR feedback, and improvement opportunities.

  Sweep protocol:
  - Find your previous report with auto.sessions.list/conversation. Avoid
    re-reporting old findings; close resolved ones and escalate recurring ones.
  - Triage recent sessions, PR feedback, and relevant read-only data sources.
  - Deep-dive at most three evidence clusters. Prefer one well-evidenced,
    automatable improvement over many shallow observations.

  Deliver per your profile instructions and always end with the four-section
  report.
mounts:
  - kind: git
    repository: acme/widgets
    mountPath: /workspace/widgets
    ref: main
    depth: 1
    auth:
      kind: githubApp
      capabilities:
        contents: read
        pullRequests: read
        issues: read
        checks: read
        actions: read
workingDirectory: /workspace/widgets
tools:
  auto:
    kind: local
    implementation: auto
  chat:
    kind: local
    implementation: chat
    auth:
      kind: connection
      provider: slack
      connection: slack
  github:
    kind: github
    tools:
      - search_pull_requests
      - pull_request_read
      - actions_list
      - actions_get
triggers:
  - event: chat.message.mentioned
    connection: slack
    where:
      $.chat.provider: slack
      $.auto.authored: false
    message: |
      {{message.author.userName}} mentioned you on Slack:

      {{message.text}}

      Channel: {{chat.channelId}}
      Thread: {{chat.threadId}}

      Reply in that thread with chat.send. If the user clearly asks for a
      sweep, run it. If required context is missing, ask for the time window,
      target agents, PRs, or data source. Otherwise, briefly explain that you
      review PR feedback, read-only data sources, and Auto session history,
      then propose concrete improvements when something is actionable.
    routing:
      kind: spawn
  - kind: heartbeat
    cron: 0 */2 * * *
    timezone: UTC
    routing:
      kind: spawn
```

The example assumes a Slack connection named `slack`; the GitHub tool reads through the project's GitHub App installation.

## Walkthrough

### A spawning heartbeat, not a delivering one

Both triggers route `spawn`, which makes this the simplest possible lifecycle: every sweep is a fresh, self-contained session. Compare the [research loop](/examples/research-loop), whose heartbeat *delivers* into a long-lived `concurrency: 1` slot — that shape suits an orchestrator holding in-flight state; this one suits a stateless auditor. The heartbeat declares no `message:`, so the session starts from the agent's `initialPrompt`, which renders the tick's payload — `{{heartbeat.scheduledAt}}` — to timestamp the sweep. Each heartbeat trigger becomes one cron schedule (`0 */2 * * *`, `timezone: UTC`); see [cron and webhooks](/reference/events/cron-and-webhooks).

### The introspection tools are the evidence base

The `auto` tool exposes a read-only `auto.sessions.*` introspection family that turns the project's history into something an agent can study:

| Tool                         | What the sweep uses it for                                                                                                           |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `auto.sessions.list`         | Triage recent sessions by status and recency; find its own previous report.                                                          |
| `auto.sessions.summary`      | Dense per-session diagnostics: timing, per-tool error stats, trigger provenance — the recommended first call on anything suspicious. |
| `auto.sessions.conversation` | Read a transcript, including its own last sweep's final message.                                                                     |
| `auto.sessions.tools`        | Paired tool call/result exchanges with durations; `errorsOnly` finds flapping tools.                                                 |
| `auto.sessions.triggers`     | What spawned a session and every delivery since — including events *dropped*, with reasons. Dead triggers show up here.              |
| `auto.sessions.search`       | Grep transcripts across a session for repeated patterns.                                                                             |

Large payloads are truncated to a byte budget by default with targeted-read recipes for recovering full content, so sweeping many sessions stays cheap. See [auto tools](/runtime/auto-tools) for the full catalog.

### Stateful across sweeps, with no state store

The sweep protocol's first step — *find your previous report* — is the whole persistence mechanism. The previous session's four-section report is durable in its transcript; `auto.sessions.list` scoped to this agent finds it; `auto.sessions.conversation` reads it. That gives consecutive sweeps memory (closures, escalations, "already reported") without a database, a file, or any state the agent could corrupt. The same trick powers the [research loop](/examples/research-loop)'s thread-as-lab-log; here the transcript itself is the log.

### Read-only by construction

Three separate mechanisms keep this agent observational:

* **A read-only mount** — every `githubApp` capability is `read`, so the checkout stages but the session's git credential cannot push. The mount is what provisions the brokered GitHub tools at all; an agent with no `githubApp` mount gets no GitHub tool access, whatever its tool list says.
* **A pared GitHub tool list** — `search_pull_requests`, `pull_request_read`, `actions_list`, `actions_get` are all reads. Without write tools in the list, the brokered proxy will not offer them, whatever the prompt says.
* **Prompt policy** for any external MCP tools you attach: read-only sources (logs, metrics, incidents) are in scope, mutations are not.

That layering matters because this agent's job is to criticize the system it lives in. Its proposals earn trust precisely because it cannot act on them unilaterally.

### From findings to PRs: closing the loop

As shipped, the agent proposes and humans dispose. The natural next step is to let accepted findings become pull requests — against application code or against `.auto/` itself. Because agents, prompts, and triggers are plain YAML in the repository, a PR that edits `.auto/agents/pr-review.yaml` gets a Sync **plan** comment on the PR showing exactly which resources change and how, and applies only after a human merges. The improvement loop stays gated by review even when the subject is the factory's own configuration.

Two ways to wire it:

* Raise the mount's capabilities to `contents: write` and `pullRequests: write`, add `create_pull_request` to the GitHub tool list, and extend the prompt: findings the evidence strongly supports become focused PRs, one finding per PR.
* Keep this agent read-only and pair it with the packaged [Shepherd](/examples/handoff): the sweep posts a finding to `#dev`, and a human hands the fix to `@auto.shepherd` with one mention.

## Install from the consolidated agent package

The packaged Self Improvement role is published in `@auto/agents`:

```yaml .auto/agents/self-improvement.yaml theme={null}
imports:
  - "@auto/agents@latest/self-improvement.yaml"
variables:
  repoFullName: acme/widgets
```

Under [GitHub Sync](/concepts/github-sync), `repoFullName` defaults from the Sync binding, so the `variables` block can be omitted. In the template's current revision Slack reporting is optional and uses a standard connection named `slack`; without it, the sweep's report is the session's final message, readable in the sessions view. Override inherited fields by declaring them in the importing file, and drop inherited entries with `remove: { triggers: [...], tools: [...] }`. See [managed templates](/reference/managed-templates).

## Adapt it

* Replace `acme/widgets`, `slack`, and `#dev`, and pick a cadence that matches your session volume — every 2 hours suits an active project; daily suits a quiet one. Sweeps that mostly find nothing are wasted spend.
* Tailor "actionable" to your team. A review-heavy team cares about expressed preferences and missing tests; an ops-heavy team cares about incident patterns and flaky tool calls.
* Attach read-only MCP tools for the data your team actually debugs with — logs, metrics, error trackers — as additional evidence sources (see [tools](/reference/tools)).
* Keep the evidence-before-verdicts standard and the three-deep-dive bound. An improvement agent that speculates gets muted within a week; one that cites transcripts gets read.

## Try it

Merge the PR and let GitHub Sync apply the resources. Rather than waiting two hours, trigger a sweep by mentioning the agent:

```text theme={null}
@self-improvement do a manual sweep of the last 24 hours: sessions, PR feedback, and anything actionable.
```

Confirm the session reads real evidence, and that the report either names concrete improvements with citations or says plainly why it needs more data. Then let the heartbeat take over.
