MA
manager.addict.bestHybrid agent apps · ready to run

Outreach Bridge Agent

OpenOutreach B2B compose + Aaron narrative + Frappe CRM schema + social proof handoff.

OpenOutreachAaronFrappehandoffCLI

Hybrid components (≥5)

B2B email + social proof bridge — separate risk surfaces.

  • OpenOutreach — ICP job JSON + docker run path
  • Aaron narrative loop — Trace→Architect→Land→Evaluate
  • Frappe DocTypes — CRM schema for accounts/jobs/leads/incidents
  • Social handoff pack — permissioned proof posts only
  • simplified-cli — optional creative assets

Runnable outreach bridge

python · outreach_agent.py
#!/usr/bin/env python3
"""Outreach Bridge Agent
Hybrids: OpenOutreach ICP pack · Aaron narrative skills · Frappe DocType schema
         · simplified-cli assets · social handoff (not email spam)
"""
from __future__ import annotations
import json, os
from dataclasses import dataclass, asdict
from pathlib import Path
from typing import Literal

Verdict = Literal["PASS", "FAIL", "INCONCLUSIVE"]

@dataclass
class R:
    name: str
    verdict: Verdict
    detail: str
    evidence: dict

def openoutreach_compose() -> R:
    # Produces onboarding payload for docker OpenOutreach — does not send mail here
    icp = os.environ.get("ICP", "VP Engineering at Series B SaaS")
    product = os.environ.get("PRODUCT", "manager.addict.best social ops plane")
    payload = {
        "product": product,
        "icp": icp,
        "channels": ["email"],  # browserless B2B — zero social ToS surface
        "followup_turns": 3,
        "self_promo_fraction": 0,  # disable freemium promo if forking
        "docker": "ghcr.io/eracle/openoutreach:latest",
    }
    path = Path(os.environ.get("OUT_DIR", ".")) / "openoutreach_job.json"
    path.write_text(json.dumps(payload, indent=2))
    return R("openoutreach", "PASS", str(path), payload)

def aaron_narrative_brief() -> R:
    brief = {
        "trace": "pain: multi-account chaos",
        "architect": "promise: one hybrid control plane",
        "land": "proof: queue+stealth+gates",
        "evaluate": "metric: publish without checkpoints",
        "gate": "SHIP",
    }
    if not brief["promise" if False else "architect"]:
        return R("aaron-narrative", "FAIL", "BLOCK empty", {})
    path = Path(os.environ.get("OUT_DIR", ".")) / "narrative_brief.json"
    path.write_text(json.dumps(brief, indent=2))
    return R("aaron-narrative", "PASS", "SHIP brief", brief)

def frappe_doctypes() -> R:
    # Schema blueprint for CRM under social/B2B manager
    types = [
        {"doctype": "SocialAccount", "fields": ["platform", "handle", "profile_path", "proxy", "health"]},
        {"doctype": "PublishJob", "fields": ["account", "media", "caption", "status", "verdict"]},
        {"doctype": "OutreachLead", "fields": ["company", "role", "email_conf", "stage"]},
        {"doctype": "IncidentEvent", "fields": ["code", "level", "action", "until"]},
    ]
    path = Path(os.environ.get("OUT_DIR", ".")) / "frappe_doctypes.json"
    path.write_text(json.dumps(types, indent=2))
    return R("frappe-schema", "PASS", f"{len(types)} DocTypes", {"path": str(path)})

def social_handoff_pack() -> R:
    # After email interest → soft social proof post (own content)
    pack = {
        "ig_story": "Customer win (permissioned) — 15s",
        "linkedin": "Lesson learned shipping multi-account ops",
        "source": "outreach-bridge",
        "rule": "own content / permissioned logos only",
    }
    path = Path(os.environ.get("OUT_DIR", ".")) / "social_handoff.json"
    path.write_text(json.dumps(pack, indent=2))
    return R("social-handoff", "PASS", str(path), pack)

def main():
    Path(os.environ.get("OUT_DIR", ".")).mkdir(parents=True, exist_ok=True)
    results = [openoutreach_compose(), aaron_narrative_brief(), frappe_doctypes(), social_handoff_pack()]
    if os.environ.get("SIMPLIFIED_API_KEY"):
        results.append(R("simplified-cli", "INCONCLUSIVE", "run ai-image externally if needed", {}))
    else:
        results.append(R("simplified-cli", "INCONCLUSIVE", "no key", {}))
    fails = [r for r in results if r.verdict == "FAIL"]
    inc = [r for r in results if r.verdict == "INCONCLUSIVE"]
    status = "FAIL" if fails else ("INCONCLUSIVE" if inc else "PASS")
    # note: simplified INCONCLUSIVE alone shouldn't block compose — treat soft
    hard_fail = fails
    status = "FAIL" if hard_fail else "PASS"
    # If only soft INCONCLUSIVE on optional tools, PASS compose
    if not hard_fail and inc:
        status = "PASS"
    report = {"status": status, "all_pass": status == "PASS", "results": [asdict(r) for r in results]}
    print(json.dumps(report, indent=2))
    Path(os.environ.get("OUT_DIR", "."), "outreach_report.json").write_text(json.dumps(report, indent=2))
    raise SystemExit(0 if report["all_pass"] else 2)

if __name__ == "__main__":
    main()
bash · openoutreach_docker.sh
# OpenOutreach side-car (B2B email — not social scraping)
docker run --pull always -it \
  -v ~/.openoutreach/data:/app/data \
  ghcr.io/eracle/openoutreach:latest
# Then load openoutreach_job.json ICP during onboarding