> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://gtm-tools.sh/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://gtm-tools.sh/_mcp/server.

# How do I track engagement state?

> Use save_reddit_thing categories and custom feeds as agent workflow state, check conversation history before a second DM, and understand what GTM Tools does not remember for you.

An agent working a channel over weeks needs to remember what it already did: which threads it replied to, which prospects it messaged, which accounts it dismissed. We give you two real places to keep that state, and one gap you have to fill yourself.

## Reddit save categories as state

`save_reddit_thing` bookmarks a post or comment to your account, and its optional `category` doubles as a workflow label. Combined with `list_reddit_saved`, that's a persistent queue living on Reddit rather than in your agent's memory:

```bash
# Queue a thread for a reply, tagged with its stage
gtm-tools reddit save \
  --from arnaudjnn \
  --url "https://www.reddit.com/r/SaaS/comments/1abcde/some_slug/" \
  --category "p0-reply"

# Read the queue back
gtm-tools reddit saved arnaudjnn --limit 50
```

Categories that work well in practice: `p0-reply` for threads worth answering today, `watching` for ones that might develop, `replied` once you've commented, `icp-lead` for a poster worth researching.

> **Warning**
>
> `category` is a **Reddit Premium feature**. On a non-Premium account, Reddit returns 403, and the tool translates that into a clear "retry without `category`, or upgrade to Premium" rather than a bare Forbidden. Without Premium you still get plain saves, just no labels, so encode the stage in your own store instead.

## Custom feeds per ICP

`create_reddit_custom_feed` builds a multireddit, which is the cheapest monitoring primitive we have: one feed per ICP, then one `list_reddit_custom_feed_posts` call reads the merged stream instead of polling each subreddit.

```bash
gtm-tools reddit create-feed \
  --from arnaudjnn \
  --name cx_saas \
  --subreddits "CustomerSuccess,SaaS,ecommerce,shopify" \
  --description "CX buyers"

# Daily scan, rising surfaces threads with early momentum
gtm-tools reddit feed-posts --from arnaudjnn --name cx_saas --sort rising --limit 50
```

Two constraints worth knowing before you script it: `name` must match `^[A-Za-z0-9_]+$` (no dashes, because Reddit's multireddit URLs reserve them), and the tool validates that client-side with a clear error rather than letting Reddit 400. Use `display_name` for the human-readable label. Reading a feed costs 1 credit; creating one costs 5.

## Avoiding a second DM to the same person

Nothing in our API prevents you from messaging someone twice. There's no idempotency key on the send tools, and no dedupe across calls: two identical `send_linkedin_message` calls send two DMs.

What you can do is check history before sending, which is usually enough:

* **`list_linkedin_conversations`** (5 credits) returns recent threads on a connected account. If the recipient is already in one, you're following up, not opening, and the message should read differently.
* **`list_reddit_inbox`** (1 credit) covers DMs, comment replies, and mentions, so you can see whether a conversation is already live.

For anything at volume, keep your own record. The minimum useful key is `(platform, recipient_handle)` with a timestamp; write it *before* the send call, not after, so a crash mid-run doesn't lose the fact that a message went out. If your outreach platform already tracks sends, that's the natural home, and the drafts our skills produce are deliberately tool-agnostic so they can flow into it.

## What we don't do for you

Stated plainly, so you build the right thing:

* **No contact database.** We fetch live per call. Nothing accumulates a person's history for you.
* **No send log.** Audit at the source: `list_linkedin_conversations`, `list_reddit_inbox`.
* **No idempotency on writes.** Retrying a send sends again.
* **No suppression list.** If someone asks not to be contacted, that has to live in your system; we'll happily message them again if you tell us to.
* **Internal caches are not your storage.** Verified emails and resolved company URLs are cached to keep repeat lookups cheap and fast, but they're an implementation detail, not a queryable store, and you shouldn't build on their timing.

Related: [Human-in-the-loop](/knowledge-base/agent-patterns/human-in-the-loop) for gating the sends themselves, and [Credit Efficiency](/credit-efficiency) for the caching patterns that keep a long-running agent cheap.