# Agents and autonomy

> You decide how much each agent may do on your site, and you can stop any of them without a deploy. Each of the 17 agents runs on a schedule in your GitHub repository at the level you set (off, report, propose or merge), and all start at report, so nothing changes until you raise one. An agent set to merge keeps asking for approval until it has a record of clean runs.

Canonical: https://heddle.pro/docs/agents

---

## The agents

| Agent | Runs | Starts at | Never above | What it does |
| Memory agent ( memory ) | Every Monday | report | propose | Learns your products, services, buyers, locations, proof points, competitors and voice, and keeps them current, so every other agent works from the same facts. |
| Research agent ( research ) | Every Monday | report | merge | Maps the searches your buyers make before they decide who to call, and checks whether Google and AI answers mention you for each one. |
| Strategy agent ( strategy ) | Every Monday | report | merge | Studies what already ranks, finds the gaps, and builds a ranked plan of pages and posts to fill them. |
| Content agent ( content ) | Every day | report | merge | Writes pages and explainers around real buyer searches and news in your field, and publishes them once every check passes. |
| Page families agent ( families ) | Every Wednesday | report | propose | Adds the next comparison, alternative, location or integration pages, in order of measured demand. |
| Writer ( writer ) | Every day | report | propose | Turns the content agent's briefs into posts, every fact from a linked source. |
| SEO agent ( seo ) | Every day | report | merge | Fixes the pages sitting just off page one: titles that lead with the phrase buyers type, direct answers, and links from pages that already rank. |
| Refresh agent ( refresh ) | Every Thursday | report | merge | Keeps improving pages after they go live, so they stay relevant as searches and AI answers change. |
| Authority agent ( authority ) | Every Tuesday | report | propose | Earns the links and listings that tell search engines and AI answers your business is worth recommending. |
| Design and development agent ( site ) | Every Tuesday | report | propose | Keeps the site fast, readable and easy to act on, so buyers understand what you offer, trust you and take the next step. |
| Follow-up agent ( followup ) | Hourly, working days | report | propose | Makes sure every enquiry gets a fast, personal answer and doesn't go cold. |
| Paid boost agent ( paid ) | Every Monday | report | propose | Plans paid search for the searches you don't rank for yet, so the pipeline keeps moving while organic grows, and retires each campaign when the page ranks. |
| Covers agent ( covers ) | Every day | off | merge | Draws a cover for every post that has none, in your brand, so the blog and every shared link show what the post is about. |
| Video agent ( video ) | Every Wednesday | off | propose | Turns a topic your buyers search into a short narrated explainer for your site and your YouTube channel. |
| Watchdog ( watchdog ) | Every hour | merge | merge | Checks every hour that every agent has run and succeeded, and emails once per problem. |
| Canary ( canary ) | Every night | merge | merge | Sends a test brief through the real pipeline every night and throws the result away, to catch a broken model, key or check before real work hits it. |
| Update agent ( update ) | Every day | propose | merge | Moves the site to the latest Heddle through one pull request, so a new check or fix arrives with the site's catalog and counts already in step. |
Run any of them by hand with heddle agent <id> <site> --dry-run to see what it would do without doing it.

## Levels

Every agent runs at one level, set per company in heddle/autonomy.json. No agent decides its own level, and none is hard-coded to merge.

| Level | What the agent does |
| off | Nothing. |
| report | Reads, decides, and emails what it would have done. Changes nothing. |
| propose | Opens a pull request or a draft. A named person approves it through a signed link before anything ships. |
| merge | Merges its own pull request once every gate passes, deploys, and reports what it did with an undo link. |
Outreach (pitches to publications) has the same four levels and one extra rule. At merge, it sends only to addresses a publication lists for editorial contact. Anything that would go through a contact form goes to a person instead.

## Earning a level

A person sets the level in autonomy.json; the code then holds merge back until it is earned. An agent configured at merge proposes until its last promoteAfterCleanRuns runs (default 5) were all clean, and merges from the next run on, without anyone touching the file again.

Runs at any level count, so an agent that ran clean at report for a week arrives at merge already earned. A clean run is one that finished, skipped nothing it needed a model for, passed every gate it held its own work to, and left no recommendation open ( recommendations.md ).

One unclean run resets the count to zero.

So the decision is the person's and the timing is the record's. To see how far an agent is from merging, count the clean runs at the end of its list in heddle/agent-state.json.

On the original site, the SEO agent ran at propose for about a month before merging its own retitles, and explainers were approved by hand for two days of clean output before they published themselves. Both were moved up because the owner asked, with the record in front of them.

## What every agent has regardless of level

- A kill switch. A repository variable named in autonomy.json. Setting it to false stops the agent at its next run, without a deploy.
- A budget floor. Agents read the remaining model and data credit before each run and stop above the floor. They never top up.
- A watchdog. An hourly job checks that each agent has succeeded recently and emails once per problem per day. An agent that fails silently is worse than no agent. Once a day it also reads Search Console; a site-level drop pauses every publishing agent until a person sets autonomy.json indexHealth.resumedAt (reliability.md).
- A canary. A nightly run of a fixed brief through the real pipeline, draft discarded, that emails only on failure. It catches a broken model, credential or check before a real run does.
- A signed approval link. Approvals are HMAC-signed links over the item and its exact content hash. The agent's own credentials cannot mark anything approved. A link for an older version of a draft does nothing.
- A report to a named person after every run that changed anything.
- A ledger. Every recommendation goes into heddle/recommendations.json and stays until it is implemented, rejected with a reason, or handed to a person with the exact step (recommendations.md).

## What never becomes autonomous

- Claiming anything not in company.json with evidence.
- Publishing under a person's byline unless that person reviewed the page. Agents may draft for an author; only the author approves. An agent-sourced post carries the company's name unless its approver is the person named. Standing consent ( publish.bylines ) is retired since 12 October 2026.
- Publishing an agent-sourced post at all without the head of content's signed approval of that exact version (content-policy.md).
- Publishing a restatement as an indexable page. An agent-sourced post that adds nothing first-hand to its sources is held back, or published noindex ( publish.informationGain, below).
- Changing a slug that has been published.
- Spending above the budget, or topping up credit.

## Publishing pace

Every agent that merges its own work spends one shared budget, set per install in autonomy.json:

- What counts. A new page an agent merges, and a substantial edit an agent merges to a page that is already live. One that adds a heading, adds or removes about a hundred words, or changes a quarter of the page's paragraphs. A retitle, a meta description or a link does not count. Neither does a page published noindex, nor anything a person merges.
- The windows. Rolling. The last 24 hours and the last 7 days, across every agent together. editsPerRun caps substantial edits in one run on top.
- A young site. Under young.ageDaysUnder days old (from pace.launched or site.json surface.launched ), or under young.indexedShareBelow of its sitemap indexed (the watchdog's index-health record), or with neither known, the lower young budget applies.
- Over the budget. The pull request is opened and left for a person, with its approval link; it never merges. The writer drafts no more agent-sourced posts than the budget has room for and leaves the rest queued ( pacedAt on the idea), which the watchdog reads as waiting by design.
- The ledger. refs/heddle/pace in the site's repository, a small JSON file written by compare-and-swap. Keys are per page, so a retry never counts twice, and two agents at once cannot both take the last slot. A ledger that cannot be read or written merges nothing.
You know it is working when the agents' reports say "held by the publishing pace budget" on the days they would have gone over, and git ls-remote origin refs/heddle/pace answers.

The origin is in lessons.md: a documentation site of about 70 pages took 18 agent notes in six days and fell out of Google's index within three days.

## Agent-sourced posts

Since 12 October 2026 no agent-sourced post publishes itself, at any level and under any setting (content-policy.md):

- agentSourced. "approve": every post waits for the head of content (the writer's approver), who gets a review email with the rendered preview, the Google-guidelines panel's readings, how the post opens, its facts with their sources, the signed approve link for that exact commit, and a reply that corrects it. "auto" is retired. It is read as "approve", the writer's ceiling stays at propose, the manifest stays gated, heddle validate warns and heddle doctor fails until the file says "approve".
- fresh. What the content agent may draft from. Dated stories inside days (2), as commentary, never a summary. demand: "report" lists measured searches and planned posts as gaps for the ideas inbox instead of filing them for the writer.
- dailyFloor. How many posts a day the install aims to have drafted. The writer drafts enough of the queue to reach it and reports a day the queue cannot.
- bylines. Retired with "auto": a person's name goes only on a page that person reviewed.
- informationGain. Every agent-sourced post is read beside its sources and the company's own first-hand material (company.json claims with evidence, its counts, a person's or the company's data in the brief's firstHand ), and asked whether it uses that material as substance. One that only restates its sources is, with "mode": "hold" (the default), declined with its reason and its draft kept in the run's reports; when no person's first-hand material was in the brief and the install takes review replies, it is parked as asked and the head of content is asked for the backstory instead. With "noindex", it is proposed with noindex: true in its front matter ( field renames it) under the company's byline, which the site must render noindex, follow and leave out of its sitemap and feeds. A reading that cannot be taken leaves the idea queued.
What it never covers. A post a person asked for. Ideas sent by email ( ideas-by-email.md ) always wait for that person's signed approval, whatever publish says.

The origin. On the source site, agent-filed explainers published themselves from 11 October 2026 once their checks passed. The next day, after Google's September spam update and its October guidance that AI content be reviewed by a person before it publishes, its owner reversed that.

Every agent post waits for a person, after a panel of decision models has read it against Google's own wording. That is a rule now, not a setting.

## Kill switches

Each agent's kill switch is a repository variable named in autonomy.json, HEDDLE_<AGENT> by default ( HEDDLE_SEO for the SEO agent). Any of off, false, 0, no, stop, disable, disabled stops the agent at its next run; unset, or any other value, lets it run. No deploy is needed:

## The recommendations ledger

Every recommendation an agent makes goes into heddle/recommendations.json, and stays there until it is closed. Read it with:

You know it is working when the daily digest has a "Recommendations, oldest first" section, and nothing in it is older than maxOpenDays without the watchdog having said so.

### What an entry is

| Field | Meaning |
| id | <agent>-<hash>, stable: the same finding raised again is the same entry |
| agent | Who raised it, or person for one added by hand |
| date | The day it was first raised |
| recommendation, evidence | What to do, and what the agent measured or read |
| status | open, implemented, rejected or needs-person |
| pr / commit / verifiedBy | What closed it ( implemented needs one) |
| reason | Why it was turned down ( rejected needs one) |
| step | Exactly what a person must do ( needs-person needs one) |
| lastSeen | The last run that raised it; a closed entry raised again keeps its status and moves this |
heddle validate fails an entry whose status lacks its field: "implemented" with nothing that shows it, "rejected" without a reason, "needs a person" without the step. A closed status without its evidence is the thing the ledger exists to stop.

### The rules

- At propose or merge, an agent addresses everything it raises. It implements it (a pull request it opens), hands it to a person with the exact step, or rejects it with a reason. One left open makes the run unclean, and unclean runs never count towards merge.
- At report, recommendations stay open. The watchdog flags any open longer than autonomy.json recommendations.maxOpenDays (7 by default), once a day, in the same alert as every other problem.
- Anything that leaves the company is a person's step at every level. Pitches, listings, replies to buyers and ad campaigns are drafted, and the entry says where the draft is and that nothing was sent.
- Hand-offs close themselves. An entry handed over as a pull request is marked implemented by the watchdog when the pull request merges, and rejected (with the date) when it is closed unmerged.
- A finding the agent re-reads closes when it is gone. Checks that run in full every time (the canary's probes, the site agent's findings, the SEO agent's indexing, headline and gate findings, the memory agent's claims) close their own entries when a later run no longer finds them, with verifiedBy naming that run. A check that did not run closes nothing.
- People close entries by editing the file. Set the status and its field, run heddle validate, commit. A person adding a recommendation of their own uses "agent": "person" and "source": "person".
Generated from the Heddle repository at e8bad8c.

## Questions

### Can an agent publish without anyone approving it?

Only an agent set to merge in autonomy.json, after its last clean runs, and only within its ceiling. Pitches, replies to buyers, ad campaigns and the company's own facts stop at propose at every level, and a post a person asked for always waits for that person.

### How do I stop an agent now?

Set its kill switch, a repository variable such as HEDDLE_SEO, to off. It stops at its next run without a deploy.
