skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
reason-machines/trending-skills364 installs

oransim-causal-marketing-twin

Causal digital twin for marketing simulation — predict campaign ROI, run counterfactual KOL swaps, and audit causal graphs before spending a dollar.

How do I install this agent skill?

npx skills add https://github.com/reason-machines/trending-skills --skill oransim-causal-marketing-twin
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubwarn

    The skill functions as a wrapper for a marketing simulation engine. It requires downloading a remote repository and installing local dependencies. A potential security risk exists in the use of Python's pickle module for loading machine learning models, which can be exploited for arbitrary code execution if the model file is compromised. Additionally, the use of LLM-backed consumer agents to process marketing creatives creates a surface for indirect prompt injection.

  • Socketwarn

    1 alert: gptAnomaly

  • Snykwarn

    Risk: MEDIUM · 1 issue

What does this agent skill do?

Oransim — Causal Digital Twin for Marketing

Skill by ara.so — Daily 2026 Skills collection.

Oransim is an open-source causal simulation engine for marketing teams. It lets you predict campaign ROI, run counterfactual "what if" scenarios (swap KOLs, reallocate budget, change platforms), and audit every prediction through a transparent 64-node causal graph — before spending a dollar.

Core capabilities:

  • Pre-launch ROI ranking across creative × KOL × budget combinations
  • Mid-campaign do()-operator rollouts (e.g. swap KOL on day 3, see 14-day path diff)
  • Post-mortem counterfactuals (what if we'd spent on 小红书 instead of 抖音?)
  • LLM-backed "soul personas" for 1M+ virtual consumer agents
  • Causal Neural Hawkes Process for temporal cascade simulation
  • Per-arm counterfactual heads (TARNet / Dragonnet architecture)

Installation

git clone https://github.com/OranAi-Ltd/oransim.git
cd oransim
pip install -e '.[dev]'

Backend (mock mode — no API key needed)

LLM_MODE=mock python -m uvicorn oransim.api:app --port 8001

Backend (real LLM pipeline)

LLM_MODE=api \
LLM_API_KEY=$YOUR_LLM_API_KEY \
LLM_MODEL=gpt-4o \
python -m uvicorn oransim.api:app --port 8001

Frontend

python -m http.server 8090 --directory frontend
# Open http://localhost:8090

Configuration

All config via environment variables (see .env.example):

# LLM mode: "mock" (deterministic stubs) or "api" (real LLM)
LLM_MODE=api

# Provider: openai (default), anthropic, gemini, qwen
LLM_PROVIDER=openai

# API key (also accepts provider-specific: OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.)
LLM_API_KEY=sk-...

# Model
LLM_MODEL=gpt-4o

# Custom base URL (DeepSeek, vLLM, etc.)
LLM_BASE_URL=https://api.deepseek.com/v1

Provider quick-reference

ProviderLLM_PROVIDERLLM_BASE_URLExample model
OpenAIopenaihttps://api.openai.com/v1gpt-4o
DeepSeekopenaihttps://api.deepseek.com/v1deepseek-chat
vLLM (local)openaihttp://localhost:8000/v1any
Anthropicanthropic(default)claude-sonnet-4-6
Geminigemini(default)gemini-2.5-flash
Qwenqwen(default)qwen-plus

Key API Endpoints

All endpoints served at http://localhost:8001.

POST /api/predict — Run a campaign simulation

import httpx

payload = {
    "campaign": {
        "name": "Summer Beauty Launch",
        "platform": "xhs",           # xhs | douyin | tiktok
        "budget": 500000,            # CNY
        "duration_days": 14,
        "creatives": [
            {"id": "vid_A", "type": "video", "duration_sec": 30},
            {"id": "vid_B", "type": "video", "duration_sec": 60},
        ],
        "kols": [
            {"id": "kol_001", "tier": "mid", "vertical": "beauty", "fans": 250000},
            {"id": "kol_002", "tier": "koc", "vertical": "skincare", "fans": 45000},
        ],
        "budget_split": {"xhs": 0.6, "douyin": 0.4},
    },
    "mode": "fast",   # "fast" (quantile baseline) | "full" (LLM agent simulation)
    "n_simulations": 100,
}

response = httpx.post("http://localhost:8001/api/predict", json=payload, timeout=120)
result = response.json()

print(result["roi"]["p50"])    # median ROI
print(result["roi"]["p35"])    # lower confidence band
print(result["roi"]["p65"])    # upper confidence band
print(result["causal_path"])   # which nodes drove the prediction

GET /api/graph/inspect — Audit the causal graph

import httpx, json

graph = httpx.get("http://localhost:8001/api/graph/inspect").json()
print(f"Nodes: {len(graph['nodes'])}")   # 64 nodes
print(f"Edges: {len(graph['edges'])}")   # 117 edges

# Find all paths from budget allocation to purchase intent
for edge in graph["edges"]:
    if edge["source"] == "budget_allocation":
        print(edge)

POST /api/sandbox/counterfactual — Mid-campaign KOL swap

import httpx

# Scenario: campaign running, day 3, swap KOL
counterfactual = httpx.post(
    "http://localhost:8001/api/sandbox/counterfactual",
    json={
        "base_campaign_id": "campaign_abc123",
        "intervention": {
            "do": {
                "kol": {"remove": ["kol_001"], "add": ["kol_003"]},
                "day": 3,
                "budget_realloc": {"kol_001_budget": "kol_003"},
            }
        },
        "rollout_days": 14,
    },
    timeout=120,
).json()

print(counterfactual["roi_diff"])          # ROI change from intervention
print(counterfactual["trajectory_diff"])   # day-by-day path difference
print(counterfactual["attribution"])       # which causal nodes shifted

POST /api/sandbox/postmortem — Platform counterfactual

import httpx

postmortem = httpx.post(
    "http://localhost:8001/api/sandbox/postmortem",
    json={
        "actuals": {
            "campaign_id": "q2_campaign",
            "spend": {"xhs": 200000, "douyin": 300000},
            "observed_roi": 1.4,
        },
        "counterfactual_alloc": {"xhs": 1.0, "douyin": 0.0},  # what if all on XHS?
    },
    timeout=120,
).json()

print(postmortem["counterfactual_roi"])   # what ROI would have been
print(postmortem["delta"])                # difference from actuals

GET /api/adapters — List available platform adapters

import httpx
adapters = httpx.get("http://localhost:8001/api/adapters").json()
# Returns: ["xhs_v1", "tiktok_agent", "douyin", ...]

Python SDK Usage (Direct Engine)

For programmatic use without the HTTP layer:

from oransim.world_model import AgentSociety
from oransim.causal import CausalGraph, do_operator
from oransim.diffusion import HawkesRollout

# 1. Build the causal graph
graph = CausalGraph.from_config("configs/default_graph.yaml")

# 2. Initialize virtual consumer society
society = AgentSociety(
    n_agents=10_000,        # scale down from 1M for local dev
    vertical="beauty",
    platform="xhs",
    llm_mode="mock",        # "mock" | "api"
)

# 3. Define campaign
campaign = {
    "budget": 200_000,
    "kols": [{"id": "kol_001", "tier": "mid", "fans": 150_000}],
    "creative_ids": ["vid_A"],
    "duration_days": 14,
}

# 4. Run baseline simulation
baseline = HawkesRollout(graph=graph, society=society)
result = baseline.run(campaign, n_simulations=50)
print(f"P50 ROI: {result.roi.p50:.2f}")

# 5. Apply do()-operator intervention
with do_operator(graph) as intervened_graph:
    intervened_graph.set("kol_assignment", "kol_002")
    intervened_graph.set("intervention_day", 3)

    counterfactual = HawkesRollout(graph=intervened_graph, society=society)
    cf_result = counterfactual.run(campaign, n_simulations=50)

print(f"Counterfactual P50 ROI: {cf_result.roi.p50:.2f}")
print(f"Delta: {cf_result.roi.p50 - result.roi.p50:.2f}")

Pre-launch ROI Ranking (All Combinations)

from itertools import product
from oransim.world_model import AgentSociety
from oransim.causal import CausalGraph
from oransim.diffusion import HawkesRollout
import pandas as pd

graph = CausalGraph.from_config("configs/default_graph.yaml")
society = AgentSociety(n_agents=5_000, vertical="beauty", platform="xhs", llm_mode="mock")

creatives = ["vid_A", "vid_B", "vid_C", "vid_D"]
kol_lists = [["kol_001"], ["kol_002"], ["kol_003"]]
budgets = [200_000, 500_000]

results = []
for creative, kols, budget in product(creatives, kol_lists, budgets):
    campaign = {"budget": budget, "kols": kols, "creative_ids": [creative], "duration_days": 14}
    rollout = HawkesRollout(graph=graph, society=society)
    r = rollout.run(campaign, n_simulations=30)
    results.append({
        "creative": creative,
        "kol": kols[0],
        "budget": budget,
        "roi_p35": r.roi.p35,
        "roi_p50": r.roi.p50,
        "roi_p65": r.roi.p65,
    })

df = pd.DataFrame(results).sort_values("roi_p50", ascending=False)
print(df.head(5).to_string())   # top 5 combinations

Common Patterns

Pattern 1: Mock mode for CI / testing

import os
os.environ["LLM_MODE"] = "mock"

from oransim.world_model import AgentSociety
society = AgentSociety(n_agents=100, vertical="beauty", platform="xhs", llm_mode="mock")
# All LLM calls return deterministic stubs — fast, free, reproducible

Pattern 2: Check if backend is in mock mode

import httpx
health = httpx.get("http://localhost:8001/health").json()
if health.get("llm_mode") == "mock":
    print("WARNING: Running in mock mode — LLM features are stubs")

Pattern 3: Inspect a prediction's causal path

result = httpx.post("http://localhost:8001/api/predict", json=payload).json()

# Every prediction includes which causal nodes fired
for node in result["causal_path"]:
    print(f"{node['id']:30s}  weight={node['weight']:.3f}  layer={node['layer']}")

Pattern 4: Load the LightGBM quantile baseline (fast mode)

import pickle, numpy as np

with open("models/lgbm_quantile_baseline.pkl", "rb") as f:
    model = pickle.load(f)

# Feature vector: [budget, n_kols, avg_fans, duration_days, platform_enc]
X = np.array([[500_000, 2, 150_000, 14, 0]])   # 0=xhs, 1=douyin
p35, p50, p65 = model.predict(X)
print(f"ROI P35={p35[0]:.2f}  P50={p50[0]:.2f}  P65={p65[0]:.2f}")

Project Structure

oransim/
├── oransim/
│   ├── api.py                  # FastAPI app + god-file (being refactored to api_routers/)
│   ├── api_routers/            # Split routers: predict, sandbox, graph, adapters
│   ├── causal/                 # SCM, do()-operator, 64-node graph, Pearl 3-step
│   ├── world_model/            # AgentSociety, IPF population synthesis, soul personas
│   ├── diffusion/              # Causal Neural Hawkes Process rollout (14-day)
│   └── adapters/               # Platform adapters: xhs_v1, tiktok_agent, douyin, ...
├── frontend/
│   ├── index.html
│   └── js/                     # Modular JS: hero, tabs, cascade animation
├── configs/
│   └── default_graph.yaml      # 64 nodes / 117 edges causal graph definition
├── models/
│   └── lgbm_quantile_baseline.pkl
├── data/                       # 21k-note OSS demo corpus
├── docs/
│   └── en/quickstart.md
└── .env.example

Troubleshooting

Backend returns mock data even with API key set

Check the yellow banner in the frontend. Verify env vars are exported:

echo $LLM_MODE    # should be "api"
echo $LLM_API_KEY # should be non-empty
# Restart the server after setting env vars — uvicorn reads them at startup

ModuleNotFoundError: oransim

Install in editable mode from the repo root:

pip install -e '.[dev]'

Simulation times out (> 120s)

Reduce agent count or use fast mode:

# In payload:
{"mode": "fast", "n_simulations": 30}
# Or reduce society size in direct SDK usage:
AgentSociety(n_agents=1_000, ...)

CORS errors when calling API from browser

The FastAPI app includes CORS middleware for localhost:8090. If using a different port:

# In oransim/api.py, update the origins list or set:
CORS_ORIGINS=http://localhost:YOUR_PORT uvicorn oransim.api:app --port 8001

Counterfactual returns identical result to baseline

In mock mode this is expected — stubs are deterministic. Switch to LLM_MODE=api for real divergence between baseline and intervention arms.

Enterprise data access (4.3M+ 小红书 notes, 2.1M+ creators)

The OSS corpus is 21k notes. For production-scale data:


Key Concepts

TermMeaning
do() operatorPearl's intervention operator — sets a variable to a value, cuts its incoming causal edges
Soul personaLLM-backed agent personality that reads actual creatives and decides engagement
Hawkes rolloutSelf-exciting point process simulating cascade of social shares over 14 days
P35/P50/P65Confidence bands on ROI — not point estimates, always a distribution
KOL tierTop (>1M fans), Mid (50k–1M), KOC (1k–50k), long-tail (<1k)
Fast modeLightGBM quantile baseline — seconds, no LLM calls
Full modeComplete agent simulation with LLM soul personas — minutes, requires LLM_MODE=api

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/reason-machines/trending-skills/oransim-causal-marketing-twin">View oransim-causal-marketing-twin on skillZs</a>