# Running marketing on agents: the fixes that were not prompts

> Our marketing and support run on a team of Soots. Nine things that went wrong in the first days, why each looked like a prompt problem, and the runtime change that fixed it for every Soot.

- URL: https://2found.dev/blog/agent-marketing-fixes-not-prompts-en/
- Published: 2026-10-17T01:39:40.521Z
- Updated: 2026-10-17T01:39:40.521Z
- Language: en

---

2found is a small team that ships several products, so our marketing, sales and support run on [Soot](https://trysoot.com). A radar reads where builders talk, a writer drafts, an editor reviews and publishes to three blogs, a support Soot answers in the chat on our sites, and a desk files what customers tell it. They run on schedules, on our own server, every day.

Most of what went wrong in the first days looked like a prompt problem. Almost none of it was. Every time we were tempted to add a line to one Soot's instructions, the real cause sat in the runtime, the tools or the way the team was wired, and fixing it there fixed it for every Soot. These are the findings, roughly in the order we hit them.

## 1. Facts belong on pages, not in prompts

Our first Soots carried product facts in their missions. A fact copied into a prompt is right on the day it is written and wrong the day the product changes, and nobody remembers which of five missions holds the copy. The fix we kept reaching for, editing the mission again, was the cause.

Now each product publishes a facts page, its site lists them in `llms.txt`, and the runtime mirrors those pages into a knowledge pool on a schedule. Every Soot looks a fact up with `knowledge_search` before stating it and says it cannot confirm what it did not find. When customers in two different conversations ask for something the pages lack, it lands in Nest as a gap for a person to fill, with the questions they asked. Updating a fact now means editing a web page.

## 2. Search matches words, not meaning

A visitor asked in Vietnamese what Soot costs. The search for "Soot giá" found 2Novel's Vietnamese pricing page, because that page shared the most words with the query, and the English Soot page that says no price is published never came up.

We did not teach the support Soot about that case. The search tool itself now tells every Soot that it matches words, that a page may be in another language than the customer's, and that hits about another product do not answer for this one. A search that finds nothing relevant is tried once more in other words or in the page's language.

## 3. Budgets break at the worst step

A support Soot capped at 7 tool calls read its two skills, searched knowledge, and had no calls left to file the customer's lead. The lead was the whole point.

Three runtime changes, no prompt changes:

- The first read of each skill in a run is free.
- The last two tool results before the cap say how many calls remain, so the Soot spends them on what only a tool can do.
- A run that hits its ceiling still delivers the answer it wrote, and it can still report a knowledge gap in that answer. Before, the visitor's run failed and an operator chat stalled until someone typed a command.

## 4. Do not offer an option you do not want used

Every tool used to accept `async`. Smaller models set it on every call, then spent a second call collecting the result. The radar ran out of calls this way before it wrote its brief, and its pack had to say "never set async".

Now only tools that can actually be slow (`web_fetch`, `web_search`, `http_request`, shell, or a pack tool that declares it runs in the background) offer the option. The warning in the pack is gone.

## 5. A schedule should only say which cycle to run

Our morning schedule used to describe the cycle step by step, and so did the editor's mission. They drifted apart within days, and the editor followed whichever it read last. The schedule now says "run one cycle as your mission describes", and the procedure exists once.

## 6. The runtime should not write to customers

While a reply was being prepared, the runtime posted a holding line in the chat. It was the one line the model did not write, so the runtime had to guess the visitor's language, and it knew only two. A chat opened on a Vietnamese page told an English visitor to wait, in Vietnamese. The same happened when a Soot handed a chat to a person.

Both lines are gone. The widget shows a progress line in its own language (received, thinking, looking it up, step 2, writing), derived from the run's events with no tool names or arguments. When a Soot hands a chat over, it writes what to tell the customer itself, in the customer's language. Every word in the transcript is now the Soot's or a team member's.

## 7. Ask a person less, and never wait on them

The team started with an approval on every post, and the approvals piled up. Asking for less only worked once we changed how a Soot asks:

- There is one list, **Cần bạn** (needs you), for approvals, decisions, hand-offs and failures.
- A question comes with up to four one-click answers, the Soot's pick marked.
- A question can name a safe default and a time. When nobody answers, the runtime takes the default (hold the post, skip the item) and the work continues.
- An approval nobody decides within 7 days expires and goes back to the Soot that asked.
- Which tools wait for a person is the host's policy, not the pack's. Nest suggests autonomy for a tool that was approved three times and never refused.

Our editor now publishes on its own. It asks only when a post would announce a price, date or partnership our pages do not state, or answer a named person. Things only a person can do, like posting a video by hand, come as one card per cycle.

## 8. Record what the customer was told

Our desk compares each customer note with the docs to find answers the support Soot missed. It flagged two leads as missed whose replies had answered them in full: the note held only the question. A note now carries whether the customer was answered and what they were told.

## 9. Shared ids need a prefix

Soots, groups, schedules and data pools are shared by the whole runtime. A second team that names its pool `marketing` reads the first team's briefs. The example we publish prefixes every id with the company's.

## The pattern

None of these fixes mentions 2found. Each one changed a tool's description, a runtime rule, a default or where a fact lives, and a Soot on someone else's runtime gets it too. When a fix needed a sentence about one product inside one Soot's prompt, it was the wrong fix.

The team we run is published as a Soot source in Soot Forge: the [marketing-team example](https://github.com/2found/soot-forge/tree/main/examples/marketing-team). Deploy it with `soot bundle --refresh ./soot-source`, then `soot source deploy ./soot-source` (the CLI needs access to the private repository; with Nest alone, recreate the same Soots, group and schedules by hand from its files). The older [`groups/marketing-team`](https://github.com/2found/soot-forge/tree/main/groups/marketing-team) template instead gates every publication on an operator approval. A walkthrough is on the Soot blog: [Set up a marketing team that runs itself with Soot](https://trysoot.com/blog/marketing-team-that-runs-itself-en).
