URL: /capabilities/publish-and-post/answer-threads · Id: `page:/capabilities/publish-and-post/answer-threads`

# Answer threads

> Each week, the 10 Reddit, Hacker News and X threads where buyers ask about your problem, each answered helpfully as you, every claim checked.

Each week, the 10 Reddit, Hacker News and X threads where buyers ask about your problem, each answered helpfully as you, every claim checked.

```text title="Run it · Ask"
Answer 10 Reddit and Hacker News threads this week where landlords ask how to track rent, spend up to $3, and show me the plan first.
```

```ts title="Run it · SDK"
import { $ } from 'startup-builder'

const result = await $.try.Post.answer({ goal: 'Answer 10 Reddit and Hacker News threads this week where landlords ask how to track rent, spend up to $3, and show me the plan first.', budget: { amount: 3, currency: 'USD' } })
```

```json title="Run it · Response"
{
  "mode": "try",
  "stored": false,
  "estimate": "About $2.30 per 10 answers",
  "sample": {
    "venue": "Reddit",
    "thread": "r/Landlord: how do you track who paid?",
    "answered": "yes",
    "named the product": "no",
    "replies": "3 by day 2"
  }
}
```

- **Kind:** Agent task
- **Price:** $2.30 per 10 answers
- **Your time:** 12 minutes
- **Approval:** Goes out on its own
- **Deepens:** [`process:content-marketing`](https://startupbuilder.dev/workflows/processes/content-marketing)

## What you get
- **10 answers** · Each week, the 10 Reddit, Hacker News and X threads where buyers ask about your problem, each answered helpfully as you, every claim checked. · [`noun:post`](https://startupbuilder.dev/business/nouns/post)
- `read` · Threads read this week.
- `fit` · Threads that cleared the `fit` score.
- `posted[]` · Each answer: site, thread, URL, and whether it named the product.
- `held[]` · Each fit thread not answered, with the reason, such as a thread full of tool pitches, where one more would read as an ad.

**Connect once:** [Reddit](/code/integrations/reddit), [Hacker News](/code/integrations/hacker-news), [X account](/code/integrations/x). **How long:** About 10 minutes.

## Trigger
It runs weekly, and when a problem post lands on a Monitor over your phrases.

```ts
every.week(($) => $.Post.answer({ phrases: 'from-map', venues: ['reddit', 'hacker-news', 'x'], take: 10 }))
```

## Steps
Your agent does these steps, one row per step; each step’s check is part of its row and its price.

| Step | Verb | Returns | Price | Approval |
| --- | --- | --- | --- | --- |
| 1. Search the problem phrases on each site | [`Keyword.search`](/code/data/keywords/search) | Threads from the last 7 days that ask about the problem | About 3.8¢ | Runs on its own |
| 2. Judge each thread’s fit | `Collection.query` | A relevance score per thread, with the line that shows the asker has the problem | About 20¢ | Runs on its own |
| 3. Write each answer as you | `Content.draft` | An answer that helps first, in your voice, naming the product only when the thread asks for tools | About 12¢ | Runs on its own |
| 4. Post on Reddit and Hacker News as you | [`Post.publish`](/code/apps/social/publish) | Each answer live in its thread, read back; X answers go through your account at $0 | About $1.92 | Goes out on its own |
| 5. Read the replies two days later | [`Keyword.search`](/code/data/keywords/search) | Replies to each answer, which hand a reply that asks for more to Answer every inbound | About 1.9¢ | Runs on its own |

Calls: `Keyword.search`, then `Collection.query`, then `Content.draft`, then `Post.publish`, then `Keyword.search`.

About $2.30 per 10 answers, each time it runs, capped at $3.00.

## Example: give it a goal
> Answer 10 Reddit and Hacker News threads this week where landlords ask how to track rent, spend up to $3, and show me the plan first.

The plan it shows runs 5 steps, priced before it spends anything; Run it above shows the result it returns.

## When something fails

| When | Then |
| --- | --- |
| An answer fails the grade | It is rewritten once with the findings; a second failure holds the thread with the reason, and that answer is not billed. |
| A site removes an answer | It is recorded with the stated reason, and the agent reads that community’s pinned posts again before its next answer there. |
| Fewer threads clear `fit` than `take` | It answers the ones that clear it and stops: “only 7 cleared the fit line” is a finished week. |
| You call it twice for one thread | It never posts twice in a thread: it is idempotent per thread. |

Each step retries three times, then falls through to the next route; one item's failure lands in `skipped` with its reason, never failing the call. Before a step would cross `maxCost` it stops and returns what it has, with a `resume` link. Each step's idempotency key is the call's key plus the step and the item: `leaseline-post-answer-1-<step>-<item>`.

## How it is graded
A second model reads each answer beside the thread, the best answers already in it and your offer. It passes when it answers the asker before it mentions anything, every claim holds against your records, and it reads like the thread’s best answers. A miss is redone at no charge.

## Change it
| Ask | Compiles to |
| --- | --- |
| Only Reddit, and never name the product. | [`Post.answer`](/capabilities/publish-and-post/answer-threads) |
| Answer within an hour of a new thread, not weekly. | [`Monitor.create`](/code/data/monitors/create) |
| Turn the best answer into a page on my site. | [`Page.answer`](/capabilities/make-content/answer-pages) |

```ts
import { $, workflow } from 'startup-builder'

export default workflow({
  name: 'post-answer',
  verb: 'Post.answer',
  input: { phrases: "string[] | 'from-map'", venues: 'string[]', take: 'integer', fit: 'number' },
  trigger: { schedule: 'weekly' },
  maxCost: 3,
  grade: { evaluator: 'the thread, its best answers, the Offer', passWhen: 'helps first; every claim holds; reads like the best answers', remedy: 'redo' },
  execute: async (ctx, { phrases = 'from-map', venues = ['reddit', 'hacker-news', 'x'], take = 10, fit = 0.7 }) => {
    const threads = await ctx.step('find', () => $.Keyword.search({ keywords: phrases, venues, since: '7d', kind: 'problem-question', maxCost: 0.05 }))
    const ranked = await ctx.step('judge', () => $.Collection.query({ rows: threads, score: 'fit', min: fit, limit: take }))
    const answers = []
    for (const t of ranked.rows) {
      const draft = await ctx.step(`write:${t.id}`, () => $.Content.draft({ kind: 'reply', thread: t, from: 'offer', mention: 'when-asked', maxCost: 0.02 }))
      answers.push(await ctx.step(`post:${t.id}`, () => $.Post.publish({ replyTo: t.url, body: draft.body, maxCost: 0.25 })))   // graded before it posts
    }
    return { read: threads.length, fit: ranked.rows.length, posted: answers }
  },
})
```

Extend it with `extends: 'Post.answer'` and `base()`, or [compose your own](/code/compose) from these steps.

## Works with
**Plays that order it:** [Community answers](/plays/community-answers), [Engagement bridge](/plays/engagement-bridge), [Give before you ask](/plays/give-first), [Owned community](/plays/owned-community), [Tools on request](/plays/request-desk).

It serves [Publish and post](/capabilities/publish-and-post), and runs in [Hands-on](/strategy/hands-on), [Launch and search](/strategy/launch-and-search). It deepens [`process:content-marketing`](https://startupbuilder.dev/workflows/processes/content-marketing).

## For agents

| Fact | Value |
| --- | --- |
| Guide | `Post.answer` |
| Guide approval | `limits` |
| Goal | Answer 10 Reddit and Hacker News threads this week where landlords ask how to track rent, spend up to $3, and show me the plan first. It may change counts, the order of steps, soft filters and the route a read takes, and it stops early when the goal is met. It never relaxes your words, raises its own budget, answers its own approval, calls a Play or acts outside your standing approval. |
| Trigger | `every.week(($) => $.Post.answer({ phrases: 'from-map', venues: ['reddit', 'hacker-news', 'x'], take: 10 }))` |
| Retry | Three times with backoff, then the next route; the same idempotency key never charges, sends or posts twice |
| Idempotency key | `leaseline-post-answer-1` |
| Lookups | A `find:` input asks unless exactly one record fits |

| Step | Action class | Seat rule that would hold it |
| --- | --- | --- |
| 1. Search the problem phrases on each site | None | None. |
| 2. Judge each thread’s fit | None | None. |
| 3. Write each answer as you | None | None. |
| 4. Post on Reddit and Hacker News as you | `publish` | None. |
| 5. Read the replies two days later | None | None. |

The amounts live once, on the hub ([approvals](https://startupbuilder.dev/agents/approvals)).

| Step | Function | Doer | Checker | Assurance | Inputs |
| --- | --- | --- | --- | --- | --- |
| 1. Search the problem phrases on each site | `code` | Code | Code checks each result against its declared type | `measured` | `$0.phrases, $0.venues` |
| 2. Judge each thread’s fit | `agentic` | The [Content lead](/capabilities/agents/content-lead) agent | A second model grades the output | `graded` | `$1.threads, $0.fit` |
| 3. Write each answer as you | `agentic` | The [Content lead](/capabilities/agents/content-lead) agent | Adversarial review by a second model: Pass, or held with the reason, such as a tool mention in a thread that asked for none | `graded` | `$2.fit, offer, $0.mention` |
| 4. Post on Reddit and Hacker News as you | `agentic` | The [Content lead](/capabilities/agents/content-lead) agent | Code reads the result back from where it landed | `measured` | `$3.passed` |
| 5. Read the replies two days later | `code` | Code | Code checks each result against its declared type | `measured` | `$4.urls` |

The doer is never the checker, and the weakest assurance on the path is the whole call’s.

## Under the hood

| Kind | What it touches |
| --- | --- |
| Systems | [Sites and content](/code/apps/sites-and-content), [Social](/code/apps/social) |
| Nouns | [`noun:keyword`](https://startupbuilder.dev/business/nouns/keyword), [`noun:collection`](https://startupbuilder.dev/business/nouns/collection), [`noun:content`](https://startupbuilder.dev/business/nouns/content), [`noun:action`](https://startupbuilder.dev/business/nouns/action), [`noun:post`](https://startupbuilder.dev/business/nouns/post) |
| Events | `Collection.queried`, `Content.drafted`, `Action.evaluated`, `Post.published` |

## Reference

| Name | Type | Default | Meaning |
| --- | --- | --- | --- |
| `phrases` | `string[] \| 'from-map'` | `'from-map'` | The problem in the buyer’s words, or the question-form terms from your Keyword opportunity map. |
| `venues` | `VenueId[]` | `['reddit', 'hacker-news', 'x']` | Where to look and answer. |
| `take` | `integer` | `10` | Answers a week, at most. It never pads: 7 good threads means 7 answers. |
| `fit` | `number` | `0.7` | The relevance score a thread needs, 0 to 1: a buyer asking about the problem, not a rival’s promo thread. |
| `mention` | `'never' \| 'when-asked'` | `'when-asked'` | Name the product only when the thread asks for tools. |
| `maxCost` | `number` | `3.00` | The most this call spends each time it runs, in USD. It stops before a step would cross it and returns what it has, with a `resume` link. |

Emits `Post.answered`. Refuses with [`max-cost`](/code/refusals#max-cost) before it spends, and with the Data calls and Accounts groups ([refusals](/code/refusals)).