Install
$ agentstack add skill-doctormozg-claude-pipelines-outreach-enrich-company ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Outreach Enrich Company
Overview
You are an orchestrator that takes a company card produced by /outreach-research and does two things, in this order:
- Deepen the dossier. Fan out five specialist enrichment subagents in parallel —
outreach-news-finder,outreach-tech-analyst,outreach-growth-analyst,outreach-scanner,outreach-contact-finder— each instructed to find data not already in the card (gap-filling, not duplicating). Their findings are merged into a new## Deeper Intelligencesection appended to the card. - Draft outreach letters. Using the original card data plus the deeper intelligence as personalization fuel, draft one letter per named Key Contact via
expert-copywriter— each subtly calibrated to the contact's inferred communication style (Social Styles, produced grounded-only byoutreach-personality-profiler) — then mandatorily naturalize each viaexpert-naturalizer. The letters are appended as a## Outreach Letterssection inside the card.
The whole pipeline is fully automatic — no approval gates, no mid-run prompts. The user invokes the skill, the skill enriches and writes letters, the card now holds them both.
When to Use
Invoke when the user has a company card (produced by /outreach-research, lives at .mz/outreach//companies/.md) and wants either richer company intelligence, outreach letters, or both. Trigger phrases:
- "enrich
.mz/outreach/.../companies/.mdand write letters" - "deepen the research on this card"
- "go deeper on `` and draft outreach"
- "write outreach letters for ``"
- "generate letters from this card"
When NOT to use
- The user has only a company name or domain and no card — run
/outreach-researchfirst (single-company mode if they want only one). - The user wants to discover companies first — use
/outreach-research. - The user wants recruiter contacts for a job application — use
/job-recruiter-infoin mz-job-outreach. - The user wants general marketing copy (landing pages, announcements, social) — use
/copywritefrom mz-creative. - The user wants letters written to a separate location than the card — this skill only writes back into the card.
Input
$ARGUMENTS— Required: an absolute or repo-relative path to a company card.mdfile. Two accepted shapes:- Research baseline:
.mz/outreach//companies/.md— direct output of/outreach-research. First activation moves it toactive/. - Active:
.mz/outreach/active/_.md— a card already activated by this skill or/outreach-update-card. The date prefix is the last interaction date; this run updates it to today. - Optional modifiers (case-insensitive, order-independent):
channels:email|linkedin|both— overrides per-contact channel auto-detection. Default: best channel per contact (email if known, else LinkedIn DM, else skip).sender:— overrides the sender voice. Inline text becomes the voice description; a path is read as a sender bio markdown file. Default: read/strategy.jsonsender_voicefield if present.enrich:only— run the deep-enrichment phase and skip letter drafting (card gets## Deeper Intelligencebut no## Outreach Letters).enrich:skip— skip the deep-enrichment phase and draft letters directly from the existing card content only.brief:— pull the local business-climate dossier from anoutreach-briefrun; the combo matching the card's sector and location seeds the letters with regional-climate angles. Default: unset (company data only).personality:off— disable reader-style calibration entirely (skip the Phase 3 profiling wave; letters use neutral structure). Default: on — role-based priorities always shape the leading angle, and footprint profiling runs automatically when a contact has a usable public profile.- Default (neither flag): both phases run.
If $ARGUMENTS is empty or no source can be resolved (see Source Resolution below), emit STATUS: BLOCKED with a clear message and stop.
Argument Parsing
Extract from $ARGUMENTS:
- user_path — the path token (everything not matching a parameter pattern). Must end in
.md. - channels_override — from
channels:(default: unset → per-contact auto-detect). - sender_override — from
sender:(default: unset → use strategy.json or fallback voice). - enrich_mode — from
enrich::only,skip, or unset (default unset = both phases run). - brief_run — optional, from
brief:; resolves to.mz/outreach//climate.json(default: unset). - personality_mode — from
personality::offdisables reader-style calibration; any other value or absent =on(default).
Source resolution
Extract the company slug from user_path's basename:
- If the basename matches
_.md(active path),company_slug= the part after the date prefix. - Otherwise (
.md),company_slug= the basename minus.md.
Then resolve source_path (the file actually read and updated by this run):
mkdir -p .mz/outreach/active
find .mz/outreach/active -maxdepth 1 -type f \
-name '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]_.md' 2>/dev/null | head -1
- If found →
source_path= the active path returned. The user-supplied path is ignored in favor of the active version (which holds the canonical accumulated history). The user may have passed a now-deleted research-baseline path; the active version is authoritative. - If not found →
source_path=user_path. The card has not been activated yet; this run will activate it.
Validate the card at source_path before any other work:
- The file exists (Read succeeds).
- The first non-empty line starts with
#(H1 = company name). - The body contains H2 headers matching the canonical card shape — at minimum
## Overview,## Key Contacts,## Outreach Recommendationmust all be present. If any are missing, emitSTATUS: BLOCKEDwith the list of missing headers.
Directory Structure
- State —
.mz/task//state.md. Source of truth across phases. - Card snapshot —
.mz/task//card_parsed.json. Structured extract of the source card, consumed by the deep-enrichment subagents in Phase 2 so they know what is ALREADY documented. - Enrichment artifacts —
.mz/task//enrichment/.json. One JSON per Phase 2 subagent (news.json,tech.json,growth.json,reputation.json,contacts.json). - Briefs —
.mz/task//briefs/.json. One brief per contact selected for drafting. - Profiles —
.mz/task//profiles/.json. One reader-style read per profiled contact (Social Style or role-priorities, evidence, confidence, calibration directive), written byoutreach-personality-profilerin Phase 3 and merged into the briefs. Absent whenpersonality:off. - Drafts —
.mz/task//drafts/_.md. One draft file per (contact, channel) pair. Each draft carries YAML frontmatter (subject,channel,recipient) followed by the body. - Card lifecycle — the card ends this run at
target_path = .mz/outreach/active/_.md. Ifsource_path != target_path, the source file is deleted in the final card-rewrite phase (move semantics). Research-baseline cards at.mz/outreach//companies/.mdand stale-dated active cards (active/_.md) are removed by this run.
task_name follows _outreach_enrich_ where ` is derived in Source Resolution (slug without date prefix or .md). Same-day collisions append v2, v3`.
` = the directory containing sourcepath when the card is still at its research-baseline location (typically .mz/outreach//companies/). The sibling strategy.json lives at /../strategy.json — read it from there for sender voice and outreach angles. When sourcepath is already an active path, falls back to the most-recently-modified .mz/outreach// directory containing a strategy.json (or default` voice if none can be located).
Core Process
Phase Overview
| # | Phase | Agent(s) | Details | | --- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | | 0 | Setup + card validation | — (orchestrator) | Inline below | | 1 | Parse card + light web enrichment | — (orchestrator + WebSearch) | Inline below | | 2 | Deep enrichment via subagents | outreach-news-finder, outreach-tech-analyst, outreach-growth-analyst, outreach-scanner, outreach-contact-finder | phases/deep_enrichment.md | | 3 | Reader profiling + draft letters | outreach-personality-profiler, expert-copywriter | phases/draft_and_finalize.md | | 4 | Naturalize letters | expert-naturalizer | phases/draft_and_finalize.md | | 5 | Rewrite card (deeper + letters) | — (orchestrator, Read + Write) | phases/draft_and_finalize.md | | 6 | Verification summary | — (orchestrator) | Inline below |
Read phases/deep_enrichment.md when you reach Phase 2 and phases/draft_and_finalize.md when you reach Phase 3. If enrich_mode == "only", Phases 3 and 4 are skipped; Phase 5 still runs to append the ## Deeper Intelligence section. If enrich_mode == "skip", Phase 2 is skipped; Phase 5 only appends the ## Outreach Letters section.
Phase 0: Setup + card validation
Parse arguments. Resolve user_path, channels_override, sender_override, enrich_mode. Run Source Resolution (see Argument Parsing) to derive company_slug and source_path. Verify source_path exists and parses as a canonical company card.
Derive:
company_slug— already set by Source Resolution (stripped of any date prefix and.md).task_name=_outreach_enrich_(truncate `to 30 chars if needed). Collision:v2,v3`.task_dir=.mz/task//.run_dir= ifsource_pathis under.mz/outreach//companies/, thendirname(dirname(source_path)); otherwise (active path) the most-recently-modified.mz/outreach//directory that contains astrategy.json, falling back todefaultvoice if none found.
mkdir -p .mz/task//enrichment
mkdir -p .mz/task//briefs
mkdir -p .mz/task//profiles
mkdir -p .mz/task//drafts
mkdir -p .mz/outreach/active
Write .mz/task//state.md:
schema_version: 2
Status: running
Phase: 0
Started:
phase_complete: false
what_remains: []
UserPath:
SourcePath:
CompanySlug:
RunDir:
ChannelsOverride:
SenderOverride:
EnrichMode:
BriefRun:
PersonalityMode:
Phase 1: Parse card + light web enrichment
Read the card. Extract structured data — do this with normal markdown reading, not a regex parser. Capture:
- Company: name (from H1), domain, sector, location, founded, size, score (from the metadata header lines).
- Overview: the
## Overviewparagraph. - Key Contacts: every numbered entry under
## Key Contacts. Each entry is**** — — [LinkedIn]() —. Extract name, title, LinkedIn URL, relevance line. Also capture the trailing**Emails**:,**Phone**:,**Company LinkedIn**:lines. Cap at 5 contacts. - Recent News: numbered entries under
## Recent News & Timing Signals. Each:**** (, , timing) —. Keep top 3 bytiming_relevance(high first). - Outreach Recommendation: the synthesizing paragraph plus the three labeled lines
**Best contact**:,**Best angle**:,**Timing**:. - Technology Profile: stack list, maturity, GitHub URL, tech blog URL.
- Growth Signals: trajectory, open roles, funding (if present).
- Red Flags: any bulleted items (or "None identified").
Persist the parsed structure to .mz/task//card_parsed.json so Phase 2 subagents can read it without re-parsing the markdown:
{
"company": { "name": "...", "slug": "...", "domain": "...", "sector": "...", "location": "...", "founded": "...", "size": "..." },
"overview": "",
"key_contacts": [ { "name": "...", "title": "...", "linkedin_url": "...", "email": "...", "relevance": "..." } ],
"recent_news": [ { "title": "...", "date": "...", "category": "...", "timing_relevance": "...", "outreach_implication": "..." } ],
"outreach_recommendation": { "summary": "...", "best_contact": "...", "best_angle": "...", "timing": "..." },
"tech_profile": { "stack": ["..."], "maturity": "...", "github_url": "...", "tech_blog_url": "..." },
"growth_signals": { "trajectory": "...", "open_roles": ["..."], "funding": "..." },
"red_flags": ["..."]
}
Read /strategy.json if it exists. Capture the sender_voice (or outreach_strategy.sender_voice) and outreach_angles fields. If the file is missing OR the field is empty, use these defaults:
sender_voice="Professional, concise, plain-spoken. No marketing register, no hype. First-person singular. Direct request, one CTA per letter."outreach_angles=["Value-first introduction citing one verified personalization signal from the card or fresh research."]
If sender_override was supplied as an argument, it overrides the strategy.json value (inline text → used directly; path → read the file).
Record strategy_source per brief: strategy.json if loaded from disk, default if fallback applied, sender_override if argument was used. If default, the final STATUS will be DONE_WITH_CONCERNS.
Local-climate context
If brief_run was supplied, read .mz/outreach//climate.json and select the combo whose industry and region best match the card's sector and location (prefer an exact region match, then industry; if none match, skip climate context and letters fall back to company data). Capture the matched combo's signals and top_outreach_angles as climate_context, carried into Phase 3 brief-building. If the file is missing, warn and continue without it.
Light web enrichment
This is a small fast pre-pass for the orchestrator to grab per-contact signals the Phase 2 subagents won't touch. The deep, multi-source enrichment happens in Phase 2 via subagents. Hard cap here: 6 calls.
Run a single parallel wave of WebSearch calls:
- 1 × WebSearch per Key Contact (up to 5) — public activity. Query:
"" "" linkedin OR podcast OR interview OR keynote. - 1 × WebSearch — anchor query for cross-referencing in Phase 2. Query:
"" news.
Capture per-contact signal strings (1–2 lines each, verbatim from the search snippet). Discard anything that cannot be cited. These signals seed Phase 3 brief-building; they are not written into the card.
Record the total number of light-pass web calls — surface in the final verification block.
Update state.md Phase field to card_parsed. If enrich_mode == "skip", advance directly to Phase 3 (handoff to phases/draft_and_finalize.md). Otherwise advance to Phase 2 (handoff to phases/deep_enrichment.md).
Phase 6: Verification summary
After Phase 5 completes, emit a visible block:
Outreach enrich-company done.
Source (read from):
Card (final): _.md>
Relocated: # yes if source_path != target_path
Task dir: .mz/task//
Enrichment mode:
Subagents dispatched: (capped at 5)
Subagents failed:
Deeper-intel fields:
Contacts drafted: (channels: ) # 0 if enrich_mode == only
Contacts skipped:
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [DoctorMozg](https://github.com/DoctorMozg)
- **Source:** [DoctorMozg/claude-pipelines](https://github.com/DoctorMozg/claude-pipelines)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.