feat: /leads-signals launch page, lead-signals skill, one-command skill install (#710)
* feat(web): /intent-signals landing page for the buyer-signals launch "Claude monitor buyer signals": built from /people-search, keeping its skill grid (now eight signal tiles from the launch film's real run) and the People Search Bench. New: a morning-run demo, a three-step 'your agent is the monitor' section (Claude Code /schedule, Codex from cron, diff against the last list), the $0.98 four-source receipt, and pay-per-check pricing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(web): /intent-signals scenes from the launch film Replace the monitor steps, the receipt table and the signal tile grid with the film's own scenes, rebuilt as HTML: a radar and signal feed that judges each post, a thread → scored companies → decision makers flow with vendor waterfall, 'treg monitors…' with evidence cards per signal, and the daily hot-leads list a scheduled run grows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(web): /intent-signals hero plays the whole film in one take The hero now runs monitor the topic → read the thread → score companies → find decision makers as one continuous, clickable demo, replacing the old hero table and the two separate scene sections. The 'treg monitors…' section goes back to the skill tile grid, each tile now a small visual scene (post, new position, news, job postings, funding, headcount chart, tech adopters, Reddit thread) instead of text rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(web): /intent-signals headline 'Claude for Signal Monitor' and the real Reddit mark Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * style(web): /intent-signals nav drops the Signals and Daily list links Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(web): /intent-signals works at every width Tablet keeps every column and a smaller radar beside the feed; phone puts the radar above the feed and the post above its thread, folds secondary columns, wraps the prompt bar and truncates names instead of overlapping. The prompt cursor now honours [hidden], and a new prompt clears the last reply before it types. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * style(web): /intent-signals headline 'Claude for Monitor Leads Signal' in Geist Pixel Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(web): /intent-signals prices from the billed run, not the film's $0.98 The launch run's LinkedIn, Reddit and X sweep billed $0.52 for 2,945 signals (4,710 with the free GitHub stargazers): $0.0002 per signal checked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(skills): lead-signals, the /intent-signals workflow as a skill Detect, qualify, contact, hand back a ranked list; optionally keep watching on the agent's own schedule with a diff against the last list. It names signal families and the words to search the catalog with, never endpoint ids, so it stays right as the catalog grows. Served at /skills/lead-signals/SKILL.md and as the third entry in the well-known skills index, like make-ugc. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(skills): lead-signals description says only when to use it; example vendors per signal Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(skills): install our skills with npx skills add superdesigndev/treg The skills CLI (skills.sh) reads skills/ and skips symlinks, so build_plugin.py now also writes real copies of the workflow skills (make-ugc, lead-signals) there, and --check keeps them in step with src/treg/web/skills. The six skills that are repo tooling carry metadata.internal so the CLI hides them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(skills): vendor-listing is repo tooling, hidden from npx skills add Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(web): /intent-signals shows the one-line skill install npx skills add superdesigndev/treg --skill lead-signals, beside the treg set-up command; both copy buttons share one handler and wrap on a phone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): treg skill bootstrap installs every public skill the registry advertises install.sh already runs it; it now also installs each skill in /.well-known/skills/index.json (make-ugc, lead-signals) into the same global agent folders as the treg skill. Best-effort, and a name from the index must be a plain slug before it becomes a directory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(skills): lead-signals sends an agent without treg to llms.txt to set up Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(web): the buyer-signals page lives at /leads-signals Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * style(web): /leads-signals tools grid shows Aviato people search instead of Apollo Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * style(web): /leads-signals nav reads Leads signals Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(web): /leads-signals served by _static_page like the other launch pages The catalog's size comes from {ENDPOINTS}/{PROVIDERS} instead of typed numbers, and the page carries the shared share image. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(context): the installer also installs the advertised workflow skills Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@@ -1,6 +1,8 @@
|
||||
---
|
||||
name: add-oauth-provider
|
||||
description: Add a provider to treg's OAuth registry (the ones treg holds its own approved app for). Use when asked to "add YouTube/Notion/Meta OAuth", "support connecting X", "add a new OAuth provider", or when a connect flow, capability picker, channel/account picker, or provider health probe needs building. Covers the code changes, the platform-side approval steps, and the pitfalls that don't announce themselves.
|
||||
metadata:
|
||||
internal: true # repo tooling: hidden from `npx skills add superdesigndev/treg`
|
||||
---
|
||||
|
||||
# Adding an OAuth provider
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
---
|
||||
name: ads-conversion-tracking
|
||||
description: Use when setting up, changing or debugging treg's own conversion tracking — the ad-click capture, the AdConversion outbox, or the Data Manager uploader — and whenever asked whether conversions are "working", "live" or "verified". Also use before claiming any part of the pipeline is proven.
|
||||
metadata:
|
||||
internal: true # repo tooling: hidden from `npx skills add superdesigndev/treg`
|
||||
---
|
||||
|
||||
# treg's ad conversion tracking — what breaks, and what "verified" actually means
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
---
|
||||
name: dev-local
|
||||
description: One-command local dev stack for tools-registry. Use when asked to "start the dev server", "run treg locally", "test login locally", "bring the stack up", or before any manual/browser test against localhost.
|
||||
metadata:
|
||||
internal: true # repo tooling: hidden from `npx skills add superdesigndev/treg`
|
||||
---
|
||||
|
||||
# dev-local — the local treg stack in one command
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
../../src/treg/web/skills/lead-signals
|
||||
@@ -2,6 +2,8 @@
|
||||
name: tools-registry-context
|
||||
description: tools-registry context + doc upkeep. Use to warm up a fresh session (orient on the architecture + recent commits) or when working on tools-registry — changing code, rules, content, data, or process (proxy · auth/secrets · API · CLI · the registry skill) — loads the relevant fragment(s) from docs/context so you act with accurate, cited context. Accepts an optional focus query (e.g. `/tools-registry-context <area>`). Also runs `/tools-registry-context sync` to update the doc fragments after changes (show → approve → apply). Mention it whenever a push to the main branch is near.
|
||||
argument-hint: "[sync | <focus query>]"
|
||||
metadata:
|
||||
internal: true # repo tooling: hidden from `npx skills add superdesigndev/treg`
|
||||
---
|
||||
|
||||
# tools-registry-context — load the right design fragment, keep docs honest
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
name: treg-page
|
||||
description: Write a treg.to agent page (/agents/<client>) or use-case page (/use-cases/<category>/<job>). Researches the real problem on Reddit and X with agent-reach BEFORE writing, so the page targets the words buyers actually use and quotes their own questions. Use when adding a page from marketing/pseo-ship-plan.md, or when asked to "write the <job> page" / "add the <agent> page".
|
||||
argument-hint: "[use-case <category>/<job> | agent <slug>]"
|
||||
metadata:
|
||||
internal: true # repo tooling: hidden from `npx skills add superdesigndev/treg`
|
||||
---
|
||||
|
||||
# treg-page — research first, then fill in the spec
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
---
|
||||
name: write-provider-skill
|
||||
description: Build a treg provider skill — the endpoint map + mistake map that lets an agent do real work on a platform API through treg's proxy. Use when adding a skill for a connected provider (Google Ads, LinkedIn, Meta Ads, TikTok, X, Instagram, Search Console), or when an existing provider skill needs verifying or extending.
|
||||
metadata:
|
||||
internal: true # repo tooling: hidden from `npx skills add superdesigndev/treg`
|
||||
---
|
||||
|
||||
# Writing a provider skill
|
||||
|
||||
@@ -7,6 +7,8 @@ description: >
|
||||
→ tests → LIVE bogus-key test → core catalog YAML → verify → scrub → validate → evidence
|
||||
ledger in the PR. Every listing ships tier-4 wiring and a per-endpoint verification table.
|
||||
The vendor-facing doc this skill implements is docs/VENDORS.md.
|
||||
metadata:
|
||||
internal: true # repo tooling: hidden from `npx skills add superdesigndev/treg`
|
||||
---
|
||||
|
||||
# Vendor listing — add a provider to the catalog
|
||||
|
||||
@@ -152,7 +152,9 @@ first and, outside it, prints which Python pip3 belongs to plus the uv one-liner
|
||||
pip fail with its "Ignored the following versions" wall (a real user hit exactly that). It also
|
||||
installs the official
|
||||
**tools-registry skill** into every detected agent via `treg skill bootstrap` (Claude Code, Cursor, Codex,
|
||||
Gemini, Copilot, OpenCode, Windsurf …), falling back on older CLIs to a Claude-only drop that curls
|
||||
Gemini, Copilot, OpenCode, Windsurf …), together with every other skill in
|
||||
`/.well-known/skills/index.json` (the workflow skills such as `make-ugc` and `lead-signals`; best-effort,
|
||||
and an index name must be a plain slug before it becomes a folder), falling back on older CLIs to a Claude-only drop that curls
|
||||
`{BASE}/skill.md` into `~/.claude/skills/treg`. Because the package is public on PyPI,
|
||||
`curl … /install.sh | sh` now works for anyone with no repo/git access needed. The **Getting started**
|
||||
dashboard view (`view==='start'`) surfaces this install command + `treg login`/`onboard`/`add`/`call` and
|
||||
|
||||
@@ -35,6 +35,7 @@ sources:
|
||||
- src/treg/web/usecase-social.html
|
||||
- src/treg/web/usecase-ads.html
|
||||
- src/treg/web/people-search.html
|
||||
- src/treg/web/leads-signals.html
|
||||
- src/treg/web/grokbot.html
|
||||
- src/treg/web/fable-gtm.html
|
||||
- src/treg/web/ugc.html
|
||||
@@ -125,7 +126,7 @@ server-side first-touch attribution across signup, first successful call and top
|
||||
| `/sitemap.xml` | **Generated**, not bundled — 80 of its URLs come from the catalog. Static pages take `lastmod` from their file's mtime, shelves from the newest mtime under `src/treg/catalog/`. |
|
||||
| `/resources` + `/use-cases/<slug>` | The outcome pages and their hub. Their sitemap rows are spread from `_USE_CASES` rather than listed by hand, so routing a new page lists it — see below. |
|
||||
| `/blog` + `/blog/people-search-bench` | A thin, hand-kept index of the launch pages (`_BLOG_LAUNCHES`, newest first, dated by the day each route shipped) and short posts (`_BLOG_POSTS`); the bench post repeats the four People Search Bench scores from `/grokbot#bench` and links there. Each post carries `BlogPosting` schema from `_blog_posting_ld` (headline, the `_BLOG_POSTS` date as published and modified, a named `Person` author, treg.to as publisher) beside its breadcrumbs, because a dated, bylined article earns the validation click and the AI citation where a bare page does not. Both are `_page()`-rendered, hosted-only, sitemapped (0.7 / 0.6) and in the route manifest. `/agents/grok-bot` (and `.md`) 301 to `/grokbot`: the launch page is the destination, the agent page was never linked as one, and the sitemap lists only `/grokbot`. |
|
||||
| `/people-search` + `/grokbot` + `/fable` + `/ugc` | The launch-campaign landings, bundled files served by their own routes through `_static_page` (placeholders filled, no-cache, an ETag so revalidation is a 304). All are first-class pages: canonical, OG tags, listed in `_SITEMAP_PAGES` at 0.8 — `/people-search` is "Claude for people search" (the enrichment launch film's destination), `/grokbot` the "Grok Bot for Outreach" animatic plus the six-bot treg team gallery (ICP Map Coach, Lookalike Scout, Rival Watch Desk, SERP Watch Team, Creator Shortlist Crew, and GTM Expert, each linked directly to its `x.ai/bot/…` page). Its nav, hero and closing CTAs remain the pair **"Setup treg"**, primary — signed in it goes to `/app`, signed out it opens the page's own sign-in modal in place (the `/people-search` pattern; the `href` `/app?ref=grokbot` is only the no-JS fallback) and stashes `treg-ref=grokbot` so the first-run welcome preselects Grok Bot, and **"Install plugin"** → the x.ai plugin page, secondary. `/fable` (file `fable-gtm.html`) is the Claude Fable 5.1 launch: one terminal session that reads the market, plans, spawns four agents and shows one result window at a time. `/ugc` (file `ugc.html`) is the AI UGC workflow article as a page: an arcads-style hero of generated clips, then the five steps told as one pinned Claude Code session on the left that crossfades between steps while the artifacts scroll on the right (trend grid, a five-model character board with real-image showcases, Seedance talking heads, the demo, hook variants and the bill), then pricing against subscription tools and the catalog grid. Its asset paths are **relative** (`media/…`, `logos/…`) so the same file previews from `file://`; that only holds while the routes stay slashless. All are registered in `bootstrap.py`'s route-ownership manifest like every other route. |
|
||||
| `/people-search` + `/leads-signals` + `/grokbot` + `/fable` + `/ugc` | The launch-campaign landings, bundled files served by their own routes through `_static_page` (placeholders filled, no-cache, an ETag so revalidation is a 304). All are first-class pages: canonical, OG tags, listed in `_SITEMAP_PAGES` at 0.8 — `/people-search` is "Claude for people search" (the enrichment launch film's destination), `/leads-signals` is "Claude for Monitor Leads Signal" (the buyer-signals launch, built from `/people-search`: the agent runs the check on its own schedule and diffs against its last list; treg itself neither schedules nor diffs), `/grokbot` the "Grok Bot for Outreach" animatic plus the six-bot treg team gallery (ICP Map Coach, Lookalike Scout, Rival Watch Desk, SERP Watch Team, Creator Shortlist Crew, and GTM Expert, each linked directly to its `x.ai/bot/…` page). Its nav, hero and closing CTAs remain the pair **"Setup treg"**, primary — signed in it goes to `/app`, signed out it opens the page's own sign-in modal in place (the `/people-search` pattern; the `href` `/app?ref=grokbot` is only the no-JS fallback) and stashes `treg-ref=grokbot` so the first-run welcome preselects Grok Bot, and **"Install plugin"** → the x.ai plugin page, secondary. `/fable` (file `fable-gtm.html`) is the Claude Fable 5.1 launch: one terminal session that reads the market, plans, spawns four agents and shows one result window at a time. `/ugc` (file `ugc.html`) is the AI UGC workflow article as a page: an arcads-style hero of generated clips, then the five steps told as one pinned Claude Code session on the left that crossfades between steps while the artifacts scroll on the right (trend grid, a five-model character board with real-image showcases, Seedance talking heads, the demo, hook variants and the bill), then pricing against subscription tools and the catalog grid. Its asset paths are **relative** (`media/…`, `logos/…`) so the same file previews from `file://`; that only holds while the routes stay slashless. All are registered in `bootstrap.py`'s route-ownership manifest like every other route. |
|
||||
| `/jev` | "How to use Jev" (file `jev.html`; the on-page headline reads "How to use Jev for GTM Automation"); the hero carries a literal "What is Jev?" heading. Sections in order: "Quick Jev 101", ONE arrow-driven deck of eleven slides (three on what jev is, five use-case demos judged live by jev with three community recordings credited and linked, three on how to use it in code) staged like the video slides: a kicker, one big header, the visual full width, description text hidden by CSS scoped to `#deck`; then the GTM recipes, whose tab bar is mirrored in the nav everywhere except while the real bar is on screen; then community posts as cards built from each post's own data (avatars and posters bundled in `media/jev/built/`, no X embed script) in a marquee that becomes a swipeable row on touch and reduced motion; then the FAQ with its JSON-LD. The use-case demo script follows the deck through a `deckslide` event, offset by the three opening slides. The recipes are three agent prompts to copy, plus a build-your-own one, each with the demo it produces underneath. Every prompt opens with a "Before you build" block: the steps are a reference implementation, not a spec, so the agent asks about the reader's own workflow, states the plan and the cost of one run, and waits for a go-ahead. Setup is then two steps: treg through `treg.to/llms.txt` (never the install one-liner), and jev as OPTIONAL. With a Vercel AI Gateway key the agent calls jev's evaluation-model endpoint; without one it judges behind the same `state`/`questions` interface itself and labels those results `judge: agent`, so the build works today and switching to jev is a one-line change. `tests/test_jev.py` pins all of it. The X launch radar recipe is **live**: `/jev/xboost.json` serves the document `treg-worker jev xboost` stores daily under Ephemeral (`jev`/`xboost`), else the bundled snapshot `media/jev/xboost-seed.json` flagged `snapshot: true`; `POST /jev/xboost/judge {url}` runs the same forensics + jev on one visitor-pasted post (5 per IP and 60 fleet-wide per hour via ratestore, 503 until `jev_treg_token` and `ai_gateway_api_key` are set) and prepends it to the document's `manual` list, which survives the daily run. treg is a client of itself in that pipeline (`application/jev_xboost.py` calls `/call/` with the demo team's token), so the receipt is a real bill. The signup-triage and signal-first-leads recipes replay bundled runs in `media/jev/*.json` with every email address replaced; `tests/test_jev.py` pins that. Same nav, footer, capture scripts, sitemap priority and `_BLOG_LAUNCHES` entry as the other landings. |
|
||||
| `/catalog` | The dashboard SPA, in public mode — the marketplace's Catalog view on an indexable URL. |
|
||||
| `/catalog/<slug>` | The same SPA, on the platform view for one shelf. Title `{Platform} API pricing: {n} endpoints priced per call \| treg.to`: the `{platform} api pricing` phrasing is the non-brand query shape that reaches the site, the brand is treg.to, no em-dash. |
|
||||
|
||||
@@ -4,6 +4,7 @@ status: shipped
|
||||
sources:
|
||||
- src/treg/web/skill.md
|
||||
- src/treg/web/skills/make-ugc/SKILL.md
|
||||
- src/treg/web/skills/lead-signals/SKILL.md
|
||||
- src/treg/routers/web.py
|
||||
- src/treg/mcp_install.py
|
||||
- scripts/build_plugin.py
|
||||
@@ -65,7 +66,7 @@ served**, because a second copy of the product's most-read page is a copy that r
|
||||
|
||||
| door | artifact | who reaches it |
|
||||
|---|---|---|
|
||||
| the installer | `install.sh` → `treg skill bootstrap` → every detected agent's skills dir | people who ran the curl one-liner |
|
||||
| the installer | `install.sh` → `treg skill bootstrap` → every detected agent's skills dir, the treg skill plus every workflow skill in `/.well-known/skills/index.json` | people who ran the curl one-liner |
|
||||
| Claude Code plugin | `.claude-plugin/` + generated `skills/treg/SKILL.md` (repo root) | `/plugin marketplace add superdesigndev/treg` |
|
||||
| Codex/ChatGPT plugin | `plugin/.codex-plugin/` + generated `plugin/skills/treg/SKILL.md` | the directory ChatGPT and Codex share. Submission runbook: [docs/PLUGIN-SUBMISSION.md](../../PLUGIN-SUBMISSION.md), test cases: [skill-openai-test-cases.md](skill-openai-test-cases.md), per-tool justifications: [skill-openai-tool-justifications.md](skill-openai-tool-justifications.md) |
|
||||
| Cursor plugin | `.cursor-plugin/marketplace.json` + generated `plugins/treg/skills/treg/SKILL.md` | the Cursor marketplace (plugin root is never the repo root) |
|
||||
@@ -73,9 +74,13 @@ served**, because a second copy of the product's most-read page is a copy that r
|
||||
| MiniMax plugin | `plugins/minimax/.minimax-plugin/plugin.json` + generated `plugins/minimax/skills/treg/SKILL.md`; `scripts/minimax_plugin.py` pre-runs their validator and builds the ZIP | the MiniMax Plugin Marketplace (MiniMax Code + MiniMax Agent), submitted by form as GitHub subdir `plugins/minimax`; skills-only because the package may hold no credential and the bootstrap omits `treg mcp install`, which cannot write a MiniMax config. See [docs/MINIMAX-PLUGIN.md](../../MINIMAX-PLUGIN.md) |
|
||||
| the domain itself | `GET /.well-known/skills/index.json` + `/.well-known/skills/treg/SKILL.md` | anything speaking the agentskills.io convention (Hermes reads this directly) |
|
||||
| a workflow skill | `GET /skills/ugc/SKILL.md` (also `/.well-known/skills/make-ugc/SKILL.md`, second entry in the index): `make-ugc`, the `/ugc` workflow as a file to follow. Source `src/treg/web/skills/make-ugc/SKILL.md`; `.agents/skills/make-ugc` is a symlink to it so the repo's own agents and the served copy never drift. It delegates to `portrait-clone` and `ugc-talking-head-video` by URL rather than repeating them | anyone the /ugc page or the onboarding "Make UGC videos" card sends here |
|
||||
| a workflow skill | `GET /skills/lead-signals/SKILL.md` (also `/.well-known/skills/lead-signals/SKILL.md`, third entry in the index): `lead-signals`, the `/leads-signals` workflow as a file to follow: detect, qualify, contact, keep watching. It names signal families and the words to search the catalog with, never endpoint ids, because the catalog changes weekly; the schedule and the diff against the last list are the agent's, not treg's. Source `src/treg/web/skills/lead-signals/SKILL.md`; `.agents/skills/lead-signals` is a symlink to it. | anyone pointed at the URL |
|
||||
|
||||
`scripts/build_plugin.py` renders every plugin copy from the one source and `--check` fails if any is
|
||||
stale (`tests/test_plugin.py`). The variants differ **only** in their prepended bootstrap, because they arrive in opposite worlds: the Codex plugin ships an MCP connector, so its
|
||||
stale (`tests/test_plugin.py`). It also writes real copies of the workflow skills (`src/treg/web/skills/*`) to
|
||||
`skills/<name>/SKILL.md`, because `npx skills add superdesigndev/treg` (skills.sh) reads `skills/` and
|
||||
skips symlinks; repo-tooling skills under `.agents/skills` and `.claude/skills` carry
|
||||
`metadata.internal: true` so that command offers only what a user should install. The variants differ **only** in their prepended bootstrap, because they arrive in opposite worlds: the Codex plugin ships an MCP connector, so its
|
||||
bootstrap says *use the tools, not the terminal*; the Claude plugin declares **no connector in its
|
||||
manifest** — so it installs with no token and nothing waits on a directory review — and its bootstrap
|
||||
does the opposite, walking the agent through `install.sh` → `treg login` → `treg mcp install` so the
|
||||
|
||||
@@ -351,6 +351,22 @@ def main() -> int:
|
||||
target.write_text(generated, encoding="utf-8")
|
||||
print(f"wrote {rel} ({len(generated.splitlines())} lines)")
|
||||
|
||||
# The workflow skills (make-ugc, lead-signals…) as real files under skills/: `npx skills add
|
||||
# superdesigndev/treg` (skills.sh) reads that folder and skips symlinks, so a link would hide them.
|
||||
for src in sorted((ROOT / "src/treg/web/skills").glob("*/SKILL.md")):
|
||||
target = ROOT / "skills" / src.parent.name / "SKILL.md"
|
||||
generated = src.read_text(encoding="utf-8").replace("{BASE}", PUBLIC_BASE)
|
||||
current = target.read_text(encoding="utf-8") if target.exists() else None
|
||||
rel = target.relative_to(ROOT)
|
||||
if check:
|
||||
if current != generated:
|
||||
print(f"STALE — {rel} does not match {src.relative_to(ROOT)}", file=sys.stderr)
|
||||
stale = True
|
||||
continue
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
target.write_text(generated, encoding="utf-8")
|
||||
print(f"wrote {rel} ({len(generated.splitlines())} lines)")
|
||||
|
||||
if stale:
|
||||
print(" regenerate with: python3 scripts/build_plugin.py", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
---
|
||||
name: lead-signals
|
||||
description: Use when the user wants to find buyers, warm or hot leads, or in-market accounts; asks about buying signals, intent signals or trigger events; wants to know who is complaining about a problem, engaging with a post, hiring for a role, changing jobs, raising money or adopting a tool; or wants to monitor a topic, a competitor or a list of accounts for people ready to buy.
|
||||
---
|
||||
|
||||
# Lead signals
|
||||
|
||||
A signal is a public fact that makes a conversation timely: someone complained about the problem you
|
||||
solve, engaged with a post about it, hired for it, raised money, switched tools.
|
||||
|
||||
Runs on treg. If it isn't set up (`treg --version` fails), read https://treg.to/llms.txt and follow it to
|
||||
install and sign in, then come back here.
|
||||
|
||||
## The run
|
||||
|
||||
1. **Detect** raw signals for the user's buyer.
|
||||
2. **Qualify.** Drop the noise; most runs discard more than half. A signal list is not a lead list.
|
||||
3. **Contact.** Company → decision maker → work email, only for rows that survived.
|
||||
4. **Hand back** a ranked list: person, company, the signal, *why now* in one line, source link, email
|
||||
if found. State coverage plainly: "1,180 engaged, 800 emails found".
|
||||
|
||||
Default for "find buyers for X" or "monitor Y": search posts about the pain on LinkedIn, X and Reddit →
|
||||
read the comments and reactions on the best posts → keep people whose title fits → roll them up by
|
||||
company and score → decision makers and emails at the top companies.
|
||||
|
||||
## Signals
|
||||
|
||||
The vendors are examples of who answers today, not a list to stick to: search, and take whatever
|
||||
the catalog ranks best now.
|
||||
|
||||
| Signal | Search the catalog for | Example vendors | Keep | Drop |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Posts and complaints | "search linkedin posts", "search reddit posts", "search x posts" | HarvestAPI, AnyAPI, ScrapeCreators | first-person pain, last 7 days, names you or a competitor | vendors, recruiters, consultants selling to the same crowd |
|
||||
| Post engagers | "linkedin post comments", "post reactions" | HarvestAPI, Fetchin | commented beats reacted; title fits | the author's colleagues, "great post" |
|
||||
| Reviews | "google reviews" | Serper, AnyAPI | low stars about the job you do | reviews older than a quarter |
|
||||
| Hiring | "job postings" | HarvestAPI, PredictLeads, Apollo | a role that implies your product, last 30 days, several roles | staffing firms, evergreen reposts |
|
||||
| Job change | "job change" | Datagma, LeadMagic | moved in the last 90 days into a company that fits; a former user | moves inside the same group |
|
||||
| Funding | "funding rounds" | PredictLeads, Aviato | last 90 days, stage fits your price | debt read as growth |
|
||||
| Tech adoption | "technology users", "tech stack" | PredictLeads, Tomba | a tool added or removed recently: a competitor or an integration | tags every site has |
|
||||
| Headcount | "headcount", "workforce" | CompanyEnrich, Akta | direction and rate in your buyer's team | jumps from an acquisition |
|
||||
| News | "company news" | PredictLeads, Akta | launch, acquisition, exec hire, last 30 days | syndicated duplicates |
|
||||
| Ads | "ads library" | Meta Ad Library, Adyntel | live campaigns: budget and an offer to position against | |
|
||||
|
||||
Anything else is a composition. A page change: scrape the page, keep a hash, compare next run. Custom
|
||||
intent: a Google search such as `"migrating from <competitor>"`. Repo stars: GitHub with the team's own
|
||||
token.
|
||||
|
||||
## Finding the endpoint
|
||||
|
||||
The catalog changes every week, so never trust a remembered endpoint id.
|
||||
|
||||
1. `treg catalog search "<the job in plain words>"`, not a vendor name.
|
||||
2. Prefer a routed `treg.*` endpoint when there is one: the team's own keys first, then providers in
|
||||
order, and most misses are free.
|
||||
3. `treg catalog get <id>`: the price, the **hit rate** (it found something), not just works (it
|
||||
returned 200), and the row's note.
|
||||
4. One small call first. Read the reported charge and `_treg.served_by`, then scale.
|
||||
5. Nothing fits: `treg catalog request "<what is missing>"`.
|
||||
|
||||
For emails use the routed finder, `treg.people.email.find`, and always send
|
||||
`X-Treg-Route-Max-Cost: 0.05`; uncapped, a miss can walk up to the dearest provider.
|
||||
|
||||
## Score
|
||||
|
||||
Fit first (no fit, no row), then timing (fresher wins), then strength (two independent signals on one
|
||||
account beat one). Every row carries its reason in the user's words.
|
||||
|
||||
## Keep watching
|
||||
|
||||
When the user wants it recurring:
|
||||
|
||||
1. Run once and report what it cost (sum the reported charges): that is the price of each run.
|
||||
2. Keep `signals.csv` keyed by person URL, signal and source URL. Later runs report only new keys. The
|
||||
first run is the baseline; say so.
|
||||
3. Schedule it with the user's agent: Claude Code `/schedule` (a cloud routine) or `/loop` (while the
|
||||
session is open), Codex `codex exec "<prompt>"` from cron, any other agent its own scheduler. The
|
||||
scheduled run needs `TREG_TOKEN` (an agent token from `treg org agent-new`) and a place for
|
||||
`signals.csv` it can read and write, such as a repo file or a sheet.
|
||||
|
||||
## Before the first list
|
||||
|
||||
Say once: outreach to EU and UK people needs a lawful basis, and suppression and unsubscribe lists
|
||||
come first. Then hand over the list; the user decides how to use it.
|
||||
@@ -0,0 +1,114 @@
|
||||
---
|
||||
name: make-ugc
|
||||
description: Make AI UGC videos end to end through treg. Pull the trending TikTok and Instagram videos in a vertical, extract the hook patterns, create a character with the same vibe as a presenter the user picks, generate 5-10 talking-head hook clips on Seedance 2.5 (less-restriction route), add a voiced demo clip, burn captions, and report the bill per clip. Use when the user asks for UGC ads, creator-style product videos, TikTok/Reels hooks, or an AI presenter for their product.
|
||||
---
|
||||
|
||||
# Make UGC videos
|
||||
|
||||
One loop, five steps, every model call through treg. The recipe behind https://treg.to/ugc.
|
||||
|
||||
Input: the product (one line), the vertical (a few keywords), and optionally reference accounts, a
|
||||
phone recording of the product, a voice-reference clip, or a character image the user already likes.
|
||||
Output: a folder with `hooks.md`, the character image and its JSON prompt, one captioned clip per
|
||||
hook, an optional voiced demo clip, and `bill.md` with what each step cost.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **treg.** Every catalog call, upload and poll goes through treg; the vendor keys stay server-side
|
||||
and the charge lands on the team's prepaid balance. If `treg --version` fails:
|
||||
```bash
|
||||
curl -fsSL https://treg.to/install.sh | sh
|
||||
treg login
|
||||
```
|
||||
`treg balance` before starting. A full run of 4 hook clips lands in the low single-digit dollars
|
||||
at 720p; say the estimate before each paid step.
|
||||
- **Two sibling skills** this one delegates to. Read each before its step, do not paraphrase them:
|
||||
- `portrait-clone` (the character): https://raw.githubusercontent.com/agentara/skills/refs/heads/main/skills/aigc/portrait-clone/SKILL.md
|
||||
- `ugc-talking-head-video` (the clips and captions): https://raw.githubusercontent.com/superdesigndev/treg/main/.agents/skills/ugc-talking-head-video/SKILL.md
|
||||
with its `scripts/seedance_treg.py` and `scripts/caption_burn.py` beside it.
|
||||
- `ffmpeg`, Python 3 with PIL. `OPENAI_API_KEY` only if you burn captions (Whisper word timings).
|
||||
|
||||
## Flow
|
||||
|
||||
Stop at the three marked points and let the user choose. Do not pick for them.
|
||||
|
||||
### 1. Find what's trending
|
||||
|
||||
Search by task, not vendor. `treg catalog search "tiktok search videos"` and
|
||||
`treg catalog search "instagram reels search by keyword"` return the routed endpoints; call them
|
||||
with the vertical's keywords, sorted by likes, last 30 days, and collect 50-150 videos. Pull
|
||||
transcripts for the 10-15 most relevant (`treg catalog search "tiktok video transcript"`). If the
|
||||
user names competitor brands, add their ads from the Meta ad library (`treg catalog search "meta ad
|
||||
library"`).
|
||||
|
||||
Write `hooks.md`: one row per video with views, the first spoken line (0-3 s), when the product is
|
||||
first named, and who is on camera. Then name the dominant pattern in one line. In agent and B2B
|
||||
software niches it is usually: a stunt or claim, a specific number, the result, then "here's how";
|
||||
the tool appears late, as the answer. Tell the user what the data said and what it cost.
|
||||
|
||||
**Stop 1.** Show 5-8 videos as candidates for the *presenter vibe* and for the *voice*. The user
|
||||
picks one of each (they can be the same video).
|
||||
|
||||
### 2. Create the character
|
||||
|
||||
If the user already has a character image, skip to step 3.
|
||||
|
||||
Grab a clean frame of the chosen presenter (`ffmpeg -ss <t> -i src.mp4 -frames:v 1 ref.jpg`) and
|
||||
run `portrait-clone` on it. It produces a locked JSON prompt: every default the image model would
|
||||
otherwise fill in is pinned, which is what stops the doll eyes and the HDR sheen. Generate the same
|
||||
JSON on at least two models through treg and let the user compare:
|
||||
|
||||
```bash
|
||||
treg call reapi.image-gen.gemini-3-pro-image --data '{"prompt": "<json>", "size": "9:16", "resolution": "2K"}'
|
||||
treg call reapi.image-gen.gpt-image-2-5 --data '{"model": "gpt-image-2.5-flare", "prompt": "<json>", "size": "1024x1536"}'
|
||||
```
|
||||
|
||||
Gemini 3 Pro Image has been the most realistic (phone-camera softness, real pores, imperfect
|
||||
teeth); GPT Image 2.5 keeps a doll pattern in the eyes. Say which is which but show both.
|
||||
|
||||
**Stop 2.** The user picks the character frame. Save it as `character.jpg` with its JSON.
|
||||
|
||||
### 3. Generate the hook clips
|
||||
|
||||
Draft 10 hooks in the pattern from step 1, each 45-75 words so it fits a 12-18 s take (the
|
||||
talking-head skill's words/4 minus 1 rule). Put them in `hooks.md` under the table.
|
||||
|
||||
**Stop 3.** The user picks 3-5.
|
||||
|
||||
Cut the voice reference from the video chosen at stop 1: a 2-15 s animated stretch, mono mp3, as
|
||||
`ugc-talking-head-video` § Voice reference describes. Then run that skill once per hook with
|
||||
`character.jpg`, the voice clip and the script. Its runner uses the Seedance 2.5 less-restriction
|
||||
route (`reapi.video-gen.seedance-2-5.unrestricted`), which accepts a realistic face and a voice clip
|
||||
as references; the default route refuses them. Quote the per-second price from
|
||||
`treg catalog get reapi.video-gen.seedance-2-5.unrestricted` before the first run, stay on 720p,
|
||||
verify each take with the skill's checks, then caption with `caption_burn.py`. Failed tasks are
|
||||
refunded, so a moderation error costs nothing but time.
|
||||
|
||||
### 4. The demo clip (optional)
|
||||
|
||||
The character does not need to be in the demo. If the user recorded the product on their phone,
|
||||
add a voiceover and captions:
|
||||
|
||||
- **With a cloned voice**, if the user has a Fish Audio (or other TTS) account: clone from the same
|
||||
voice-reference clip, read the demo script, and tell them it runs on their key, not treg.
|
||||
- **Without one**, skip the clone: the demo plays under the hook clip with captions only, or with
|
||||
the hook clip's own audio continuing. Say which you did.
|
||||
|
||||
Stitch demo and captions with ffmpeg and the skill's `caption_burn.py`, keeping 9:16 and 720p.
|
||||
|
||||
### 5. Put it together
|
||||
|
||||
For each picked hook: hook clip, then the demo clip if there is one, concatenated with ffmpeg
|
||||
(`-c copy` when the encodes match, re-encode otherwise). Name the files by hook. Write `bill.md`
|
||||
from `treg calls` (or the prices you quoted): the trend pull, the character runs, each clip, and
|
||||
the total divided by the number of finished clips. Hand over the folder and say what you could not
|
||||
verify yourself: voice likeness and lip-sync are judged by ear and eye, not by the transcript checks.
|
||||
|
||||
## Rules
|
||||
|
||||
- Every generation and reference upload goes through `treg call` and `treg host`. Never hand a
|
||||
vendor a paste-host link, and never hold a vendor key for this loop.
|
||||
- State the price before each paid step. When you call an endpoint directly rather than through
|
||||
the runner, send treg's max-cost header so one task cannot exceed the price you quoted.
|
||||
- Rerun one thing at a time; there is no seed, and a rerun can regress something else.
|
||||
- The three stops are the product. A run that skips them makes clips nobody asked for.
|
||||
@@ -149,6 +149,7 @@ _CONTROL_ROUTE_KEYS: frozenset[RouteKey] = frozenset({
|
||||
('/integrate.md', ('GET',), 'integrate_md'),
|
||||
('/skill.md', ('GET',), 'skill_md'),
|
||||
('/skills/ugc/SKILL.md', ('GET',), 'make_ugc_skill_md'),
|
||||
('/skills/lead-signals/SKILL.md', ('GET',), 'lead_signals_skill_md'),
|
||||
('/feedback.md', ('GET',), 'feedback_md'),
|
||||
('/favicon.ico', ('GET',), 'favicon'),
|
||||
('/favicon.svg', ('GET',), 'favicon'),
|
||||
@@ -170,6 +171,7 @@ _CONTROL_ROUTE_KEYS: frozenset[RouteKey] = frozenset({
|
||||
('/gpt6', ('GET',), 'gpt6_page'),
|
||||
('/ugc', ('GET',), 'ugc_page'),
|
||||
('/people-search', ('GET',), 'people_search_page'),
|
||||
('/leads-signals', ('GET',), 'leads_signals_page'),
|
||||
('/jev', ('GET',), 'jev_page'),
|
||||
('/jev/xboost.json', ('GET',), 'jev_xboost_json'),
|
||||
('/jev/xboost/judge', ('POST',), 'jev_xboost_judge'),
|
||||
@@ -185,6 +187,7 @@ _CONTROL_ROUTE_KEYS: frozenset[RouteKey] = frozenset({
|
||||
('/.well-known/skills/index.json', ('GET',), 'well_known_skills_index'),
|
||||
('/.well-known/skills/treg/SKILL.md', ('GET',), 'well_known_skill_md'),
|
||||
('/.well-known/skills/make-ugc/SKILL.md', ('GET',), 'well_known_make_ugc_md'),
|
||||
('/.well-known/skills/lead-signals/SKILL.md', ('GET',), 'well_known_lead_signals_md'),
|
||||
('/connect-demo', ('GET',), 'connect_demo_page'),
|
||||
('/connect-demo/callback', ('GET',), 'connect_demo_callback'),
|
||||
('/help', ('GET',), 'support_page'),
|
||||
|
||||
@@ -3958,9 +3958,31 @@ def cmd_skill_bootstrap(args, cfg) -> None:
|
||||
print(f" (removed the old tools-registry skill folder — renamed to treg)")
|
||||
except OSError:
|
||||
pass
|
||||
# The other public skills this registry advertises (make-ugc, lead-signals, …): the same well-known
|
||||
# index `npx skills add` reads, so that one list decides what ships. Best-effort: the treg skill is
|
||||
# already in place, so a miss here never fails the install.
|
||||
extra = []
|
||||
try:
|
||||
idx = httpx.get(f"{base_url}/.well-known/skills/index.json", timeout=15, follow_redirects=True).json()
|
||||
for entry in idx.get("skills", []):
|
||||
name = str(entry.get("name", ""))
|
||||
# the name becomes a directory: only a plain slug, never a path the server could steer
|
||||
if name == "treg" or not re.fullmatch(r"[a-z0-9][a-z0-9-]{0,63}", name):
|
||||
continue
|
||||
r = httpx.get(f"{base_url}/.well-known/skills/{name}/SKILL.md", timeout=15, follow_redirects=True)
|
||||
if r.status_code == 200 and r.text.startswith("---"):
|
||||
extra.append((name, r.text))
|
||||
except Exception: # noqa: BLE001 — optional extras; the treg skill already installed
|
||||
pass
|
||||
for name, text in extra:
|
||||
for b in bases:
|
||||
(b / name).mkdir(parents=True, exist_ok=True)
|
||||
(b / name / "SKILL.md").write_text(text)
|
||||
print(f" ✓ {name} → {len(bases)} location(s)")
|
||||
detected = _agents.detect_installed()
|
||||
tail = f"detected: {', '.join(detected)}" if detected else "no agents detected — used sensible defaults"
|
||||
print(f"\nInstalled the treg skill into {n} location(s) ({tail}).")
|
||||
names = ", ".join(["treg"] + [nm for nm, _ in extra])
|
||||
print(f"\nInstalled {names} into {n} location(s) ({tail}).")
|
||||
|
||||
|
||||
def cmd_agents_ls(args, cfg) -> None:
|
||||
|
||||
@@ -3304,6 +3304,7 @@ _SITEMAP_PAGES: tuple[tuple[str, str, str], ...] = (
|
||||
("/support", "support.html", "0.4"),
|
||||
("/connectors/claude", "claude-connector.html", "0.6"),
|
||||
("/people-search", "people-search.html", "0.8"),
|
||||
("/leads-signals", "leads-signals.html", "0.8"),
|
||||
("/grokbot", "grokbot.html", "0.8"),
|
||||
("/fable", "fable-gtm.html", "0.8"),
|
||||
("/gpt6", "astra.html", "0.8"),
|
||||
@@ -3540,6 +3541,13 @@ async def make_ugc_skill_md():
|
||||
return _serve_md("skills/make-ugc/SKILL.md")
|
||||
|
||||
|
||||
@app.get("/skills/lead-signals/SKILL.md", include_in_schema=False)
|
||||
async def lead_signals_skill_md():
|
||||
"""The lead-signals skill: the /leads-signals workflow (detect, qualify, contact, keep watching)
|
||||
as a file an agent can follow. Bundled like make-ugc; `.agents/skills/lead-signals` links to it."""
|
||||
return _serve_md("skills/lead-signals/SKILL.md")
|
||||
|
||||
|
||||
@app.get("/feedback.md", include_in_schema=False)
|
||||
async def feedback_md():
|
||||
return _serve_md("feedback.md")
|
||||
@@ -3729,6 +3737,13 @@ async def people_search_page(request: Request):
|
||||
return _static_page("people-search.html", request)
|
||||
|
||||
|
||||
@app.get("/leads-signals", include_in_schema=False)
|
||||
async def leads_signals_page(request: Request):
|
||||
"""Landing page for the buyer-signals launch ("Claude for Monitor Leads Signal"). Built from the
|
||||
/people-search page and served the same way: canonical, in the sitemap, relative asset paths."""
|
||||
return _static_page("leads-signals.html", request)
|
||||
|
||||
|
||||
@app.get("/jev", include_in_schema=False)
|
||||
async def jev_page(request: Request):
|
||||
"""Landing page for jev + treg ("jev for GTM engineers"): three agent recipes, each with a prompt
|
||||
@@ -3814,6 +3829,8 @@ async def jev_xboost_judge(request: Request, db: AsyncSession = Depends(get_sess
|
||||
# chronological (newest first), not alphabetical.
|
||||
_BLOG_LAUNCHES: list[tuple[str, str, str, str]] = [
|
||||
# (slug, title, date, one-line blurb)
|
||||
("/leads-signals", "Claude for Monitor Leads Signal", "2026-09-28",
|
||||
"Your agent checks hiring, funding, job changes and social chatter on a schedule, and reports what's new."),
|
||||
("/jev", "How to use Jev", "2026-09-20",
|
||||
"What Jev is and how to use it: live examples, use cases, code, and GTM automation recipes."),
|
||||
("/ugc", "AI UGC Videos for $0.67 a Clip", "2026-09-15",
|
||||
@@ -4158,9 +4175,11 @@ async def well_known_skills_index():
|
||||
"""
|
||||
fm = _skill_frontmatter()
|
||||
ugc = _skill_frontmatter("skills/make-ugc/SKILL.md")
|
||||
sig = _skill_frontmatter("skills/lead-signals/SKILL.md")
|
||||
return JSONResponse({"skills": [
|
||||
{"name": fm.get("name", "treg"), "description": fm.get("description", ""), "files": ["SKILL.md"]},
|
||||
{"name": ugc.get("name", "make-ugc"), "description": ugc.get("description", ""), "files": ["SKILL.md"]},
|
||||
{"name": sig.get("name", "lead-signals"), "description": sig.get("description", ""), "files": ["SKILL.md"]},
|
||||
]})
|
||||
|
||||
|
||||
@@ -4179,6 +4198,12 @@ async def well_known_make_ugc_md():
|
||||
return _serve_md("skills/make-ugc/SKILL.md")
|
||||
|
||||
|
||||
@app.get("/.well-known/skills/lead-signals/SKILL.md", include_in_schema=False)
|
||||
async def well_known_lead_signals_md():
|
||||
"""The third entry `index.json` promises; the same file as /skills/lead-signals/SKILL.md."""
|
||||
return _serve_md("skills/lead-signals/SKILL.md")
|
||||
|
||||
|
||||
@app.get("/connect-demo", include_in_schema=False)
|
||||
async def connect_demo_page(request: Request):
|
||||
"""A page that PRETENDS to be someone else's app, so the OAuth flow can be seen end to end.
|
||||
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 27 KiB |
@@ -0,0 +1,83 @@
|
||||
---
|
||||
name: lead-signals
|
||||
description: Use when the user wants to find buyers, warm or hot leads, or in-market accounts; asks about buying signals, intent signals or trigger events; wants to know who is complaining about a problem, engaging with a post, hiring for a role, changing jobs, raising money or adopting a tool; or wants to monitor a topic, a competitor or a list of accounts for people ready to buy.
|
||||
---
|
||||
|
||||
# Lead signals
|
||||
|
||||
A signal is a public fact that makes a conversation timely: someone complained about the problem you
|
||||
solve, engaged with a post about it, hired for it, raised money, switched tools.
|
||||
|
||||
Runs on treg. If it isn't set up (`treg --version` fails), read {BASE}/llms.txt and follow it to
|
||||
install and sign in, then come back here.
|
||||
|
||||
## The run
|
||||
|
||||
1. **Detect** raw signals for the user's buyer.
|
||||
2. **Qualify.** Drop the noise; most runs discard more than half. A signal list is not a lead list.
|
||||
3. **Contact.** Company → decision maker → work email, only for rows that survived.
|
||||
4. **Hand back** a ranked list: person, company, the signal, *why now* in one line, source link, email
|
||||
if found. State coverage plainly: "1,180 engaged, 800 emails found".
|
||||
|
||||
Default for "find buyers for X" or "monitor Y": search posts about the pain on LinkedIn, X and Reddit →
|
||||
read the comments and reactions on the best posts → keep people whose title fits → roll them up by
|
||||
company and score → decision makers and emails at the top companies.
|
||||
|
||||
## Signals
|
||||
|
||||
The vendors are examples of who answers today, not a list to stick to: search, and take whatever
|
||||
the catalog ranks best now.
|
||||
|
||||
| Signal | Search the catalog for | Example vendors | Keep | Drop |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Posts and complaints | "search linkedin posts", "search reddit posts", "search x posts" | HarvestAPI, AnyAPI, ScrapeCreators | first-person pain, last 7 days, names you or a competitor | vendors, recruiters, consultants selling to the same crowd |
|
||||
| Post engagers | "linkedin post comments", "post reactions" | HarvestAPI, Fetchin | commented beats reacted; title fits | the author's colleagues, "great post" |
|
||||
| Reviews | "google reviews" | Serper, AnyAPI | low stars about the job you do | reviews older than a quarter |
|
||||
| Hiring | "job postings" | HarvestAPI, PredictLeads, Apollo | a role that implies your product, last 30 days, several roles | staffing firms, evergreen reposts |
|
||||
| Job change | "job change" | Datagma, LeadMagic | moved in the last 90 days into a company that fits; a former user | moves inside the same group |
|
||||
| Funding | "funding rounds" | PredictLeads, Aviato | last 90 days, stage fits your price | debt read as growth |
|
||||
| Tech adoption | "technology users", "tech stack" | PredictLeads, Tomba | a tool added or removed recently: a competitor or an integration | tags every site has |
|
||||
| Headcount | "headcount", "workforce" | CompanyEnrich, Akta | direction and rate in your buyer's team | jumps from an acquisition |
|
||||
| News | "company news" | PredictLeads, Akta | launch, acquisition, exec hire, last 30 days | syndicated duplicates |
|
||||
| Ads | "ads library" | Meta Ad Library, Adyntel | live campaigns: budget and an offer to position against | |
|
||||
|
||||
Anything else is a composition. A page change: scrape the page, keep a hash, compare next run. Custom
|
||||
intent: a Google search such as `"migrating from <competitor>"`. Repo stars: GitHub with the team's own
|
||||
token.
|
||||
|
||||
## Finding the endpoint
|
||||
|
||||
The catalog changes every week, so never trust a remembered endpoint id.
|
||||
|
||||
1. `treg catalog search "<the job in plain words>"`, not a vendor name.
|
||||
2. Prefer a routed `treg.*` endpoint when there is one: the team's own keys first, then providers in
|
||||
order, and most misses are free.
|
||||
3. `treg catalog get <id>`: the price, the **hit rate** (it found something), not just works (it
|
||||
returned 200), and the row's note.
|
||||
4. One small call first. Read the reported charge and `_treg.served_by`, then scale.
|
||||
5. Nothing fits: `treg catalog request "<what is missing>"`.
|
||||
|
||||
For emails use the routed finder, `treg.people.email.find`, and always send
|
||||
`X-Treg-Route-Max-Cost: 0.05`; uncapped, a miss can walk up to the dearest provider.
|
||||
|
||||
## Score
|
||||
|
||||
Fit first (no fit, no row), then timing (fresher wins), then strength (two independent signals on one
|
||||
account beat one). Every row carries its reason in the user's words.
|
||||
|
||||
## Keep watching
|
||||
|
||||
When the user wants it recurring:
|
||||
|
||||
1. Run once and report what it cost (sum the reported charges): that is the price of each run.
|
||||
2. Keep `signals.csv` keyed by person URL, signal and source URL. Later runs report only new keys. The
|
||||
first run is the baseline; say so.
|
||||
3. Schedule it with the user's agent: Claude Code `/schedule` (a cloud routine) or `/loop` (while the
|
||||
session is open), Codex `codex exec "<prompt>"` from cron, any other agent its own scheduler. The
|
||||
scheduled run needs `TREG_TOKEN` (an agent token from `treg org agent-new`) and a place for
|
||||
`signals.csv` it can read and write, such as a repo file or a sheet.
|
||||
|
||||
## Before the first list
|
||||
|
||||
Say once: outreach to EU and UK people needs a lawful basis, and suppression and unsubscribe lists
|
||||
come first. Then hand over the list; the user decides how to use it.
|
||||
@@ -801,6 +801,15 @@
|
||||
"name": "make_ugc_skill_md",
|
||||
"path": "/skills/ugc/SKILL.md"
|
||||
},
|
||||
{
|
||||
"kind": "APIRoute",
|
||||
"methods": [
|
||||
"GET",
|
||||
"HEAD"
|
||||
],
|
||||
"name": "lead_signals_skill_md",
|
||||
"path": "/skills/lead-signals/SKILL.md"
|
||||
},
|
||||
{
|
||||
"kind": "APIRoute",
|
||||
"methods": [
|
||||
@@ -963,6 +972,15 @@
|
||||
"name": "people_search_page",
|
||||
"path": "/people-search"
|
||||
},
|
||||
{
|
||||
"kind": "APIRoute",
|
||||
"methods": [
|
||||
"GET",
|
||||
"HEAD"
|
||||
],
|
||||
"name": "leads_signals_page",
|
||||
"path": "/leads-signals"
|
||||
},
|
||||
{
|
||||
"kind": "APIRoute",
|
||||
"methods": [
|
||||
@@ -1147,6 +1165,15 @@
|
||||
"name": "well_known_make_ugc_md",
|
||||
"path": "/.well-known/skills/make-ugc/SKILL.md"
|
||||
},
|
||||
{
|
||||
"kind": "APIRoute",
|
||||
"methods": [
|
||||
"GET",
|
||||
"HEAD"
|
||||
],
|
||||
"name": "well_known_lead_signals_md",
|
||||
"path": "/.well-known/skills/lead-signals/SKILL.md"
|
||||
},
|
||||
{
|
||||
"kind": "APIRoute",
|
||||
"methods": [
|
||||
|
||||
@@ -59,3 +59,30 @@ def test_detect_installed_reads_markers(monkeypatch, tmp_path):
|
||||
def test_claude_config_dir_override(monkeypatch, tmp_path):
|
||||
monkeypatch.setenv("CLAUDE_CONFIG_DIR", str(tmp_path / "cc"))
|
||||
assert ag.global_dir("claude-code") == tmp_path / "cc" / "skills"
|
||||
|
||||
|
||||
def test_skill_bootstrap_installs_every_advertised_skill(monkeypatch, tmp_path, capsys):
|
||||
"""`treg skill bootstrap` (what install.sh runs) drops the treg skill AND every other skill the
|
||||
registry's well-known index advertises, and never turns a hostile name into a path."""
|
||||
from types import SimpleNamespace
|
||||
|
||||
from treg import cli
|
||||
|
||||
pages = {
|
||||
"/skill.md": "---\nname: treg\n---\n",
|
||||
"/.well-known/skills/index.json": {"skills": [{"name": "treg"}, {"name": "lead-signals"}, {"name": "../evil"}]},
|
||||
"/.well-known/skills/lead-signals/SKILL.md": "---\nname: lead-signals\n---\n",
|
||||
}
|
||||
|
||||
def fake_get(url, **_):
|
||||
body = pages.get(url.removeprefix("https://reg.example"), "")
|
||||
return SimpleNamespace(status_code=200 if body else 404, text=body if isinstance(body, str) else "",
|
||||
json=lambda: body, raise_for_status=lambda: None)
|
||||
|
||||
monkeypatch.setattr(cli.httpx, "get", fake_get)
|
||||
monkeypatch.setattr(ag, "resolve_targets", lambda **_: [tmp_path / "skills"])
|
||||
monkeypatch.delenv("TREG_TOKEN", raising=False)
|
||||
cli.cmd_skill_bootstrap(SimpleNamespace(project=False, all_agents=False), {"base_url": "https://reg.example"})
|
||||
installed = sorted(p.parent.name for p in (tmp_path / "skills").glob("*/SKILL.md"))
|
||||
assert installed == ["lead-signals", "treg"]
|
||||
assert not (tmp_path / "evil").exists()
|
||||
|
||||
@@ -18,7 +18,7 @@ async def test_well_known_skills_index_advertises_the_skill(clients):
|
||||
r = await clients.get("/.well-known/skills/index.json")
|
||||
assert r.status_code == 200
|
||||
skills = r.json()["skills"]
|
||||
assert [s["name"] for s in skills] == ["treg", "make-ugc"]
|
||||
assert [s["name"] for s in skills] == ["treg", "make-ugc", "lead-signals"]
|
||||
entry = skills[0]
|
||||
assert entry["name"] == "treg"
|
||||
assert entry["files"] == ["SKILL.md"]
|
||||
@@ -51,3 +51,12 @@ async def test_make_ugc_skill_is_served_and_advertised(clients):
|
||||
assert f"description: {idx['description']}" in r.text
|
||||
|
||||
|
||||
async def test_lead_signals_skill_is_served_and_advertised(clients):
|
||||
"""The /leads-signals workflow as a skill, served and indexed exactly like make-ugc."""
|
||||
r = await clients.get("/skills/lead-signals/SKILL.md")
|
||||
assert r.status_code == 200 and r.text.startswith("---\nname: lead-signals")
|
||||
assert "{BASE}" not in r.text
|
||||
wk = await clients.get("/.well-known/skills/lead-signals/SKILL.md")
|
||||
assert wk.text == r.text
|
||||
idx = (await clients.get("/.well-known/skills/index.json")).json()["skills"][2]
|
||||
assert f"description: {idx['description']}" in r.text
|
||||
|
||||