← Playbooks

Role playbook

#Marketing Agent: pacing i zmiana budżetu Ads (THARAN)

Cel: codziennie sprawdzić tempo wydatków Ads względem planu i rezerwacji, zapisać decyzję w dzienniku i zaproponować zmianę budżetu dziennego. Zmiana powyżej ±10 %/dzień kończy się jako Approval (202), o którym decyduje Owner.

Passport: szablon marketing (applyTemplate("marketing", { business_id, limits_currency: "PLN" })): finances:observe@business, ads:execute@business ≤ 500/2 000/10 000 PLN, ±10 %/dzień, subscriptions:observe@all, decisions:execute@business. Brak: personal, inne biznesy, expenses, budget_reserve.

#System prompt (skopiuj)

You are the Marketing Agent for THARAN in Operlance. Start every session with get_business_context(business_id) and read coverage before trusting any total. Compare ad spend against the plan and the reservation (planned, reserved and actual are separate numbers, never sum them). Before proposing a budget change call create_decision with a measurable expected[] (metric, value, horizon_days). Propose changes with propose_ad_budget_change using DAILY budgets; a change above 10 % per day becomes an approval that the owner decides, so give a clear reason. Never record expenses or reservations: you have no grant for them, and asking for one is request_permission, not a workaround. Report numbers with their data_class and say when data is estimated or coverage is below 80 %.

#Sekwencja

  1. Kontekst biznesu (jedno wywołanie zamiast sześciu).
{
 "data": {
  "business": {
   "id": "<business:tharan>",
   "name": "THARAN",
   "currency": "USD"
  },
  "projects": [
   {
    "id": "<project:iOS>",
    "name": "iOS"
   },
   {
    "id": "<project:US Ads>",
    "name": "US Ads"
   },
   {
    "id": "<project:Web App>",
    "name": "Web App"
   }
  ],
  "summary_30d": {
   "from": "2026-08-20",
   "to": "2026-09-18",
   "revenue_minor": 2228800,
   "costs": {
    "planned_minor": 636253,
    "reserved_minor": 500000,
    "actual_minor": 997430,
    "variance_minor": 361177
   },
   "result_minor": 1231370,
   "recurring_burn_minor": 997430,
   "runway_days": 114,
   "revenue_delta_minor": 0,
   "top_cost_changes": [
    {
     "category": "ads",
     "actual_minor": 658767,
     "delta_minor": 29004
…
  1. Wydatki Ads per platforma z pacingiem.
{
 "data": {
  "period": {
   "from": "2026-09-01",
   "to": "2026-09-18"
  },
  "currency": "USD",
  "totals": {
   "spend": {
    "planned_minor": 600000,
    "reserved_minor": 277280,
    "actual_minor": 626000,
    "variance_minor": 26000
   },
   "metrics": {
    "impressions": 506000,
    "clicks": 10100,
    "conversions": 199,
    "conversion_value_minor": 1355000,
    "cpa_minor": 3146,
    "cpc_minor": 62,
    "ctr": 0.02,
    "roas": 2.16
   },
   "pacing": {
    "period_elapsed_pct": 94.4,
    "budget_used_pct": 104.3,
    "status": "on_track",
    "projected_exhaustion_on": "2026-09-17",
    "reasons": [
     {
      "code": "budget_exhausted",
      "message": "Budżet wykorzystany w 104.3%."
     }
    ]
   },
   "unallocated_reserved_minor": 0
  },
  "platforms": [
   {
…
  1. Dziennik decyzji przed działaniem (mierzalne oczekiwanie, horyzont 7 dni).
{
 "status": "executed",
 "data": {
  "id": "<id-36>",
  "owner_id": "<id-37>",
  "type": "agent_action",
  "state": "actual",
  "status": "confirmed",
  "amount_minor": 0,
  "currency": "USD",
  "direction": null,
  "business_id": "<business:tharan>",
  "personal": false,
  "project_id": null,
  "occurred_on": "2026-09-18",
  "category": null,
  "description": "Increase Google Ads daily budget 100 → 130 PLN",
  "subscription_id": null,
  "reservation_id": null,
  "integration_id": null,
  "external_id": null,
  "supersedes_event_id": null,
  "provenance": {
   "reason": "Google CPA lower than Meta; shift budget",
   "source": {
    "type": "AI_AGENT",
    "agent_id": "<id-38>",
    "approval_id": null,
    "external_id": null,
    "integration_id": null
   },
   "confidence": 0.9,
   "data_class": "agent_reported",
   "recorded_at": "2026-09-18T…Z"
  },
  "payload": {
   "action": "create_decision",
   "params": {
    "refs": [],
    "title": "Increase Google Ads daily budget 100 → 130 PLN",
…
  1. Propozycja zmiany budżetu dziennego o +30 % (ponad ±10 % z Passportu → 202 pending_approval).
{
 "status": "pending_approval",
 "approval_id": "<id-40>",
 "coverage": {
  "coverage_pct": 0.74,
  "domains": {
   "revenue": {
    "status": "accurate",
    "sources": [
     "STRIPE_API"
    ],
    "last_sync_at": "2026-09-18T…Z"
   },
   "ad_spend": {
    "status": "accurate",
    "sources": [
     "GOOGLE_ADS_API",
     "META_API"
    ],
    "last_sync_at": "2026-09-18T…Z"
   },
   "subscriptions": {
    "status": "incomplete",
    "sources": [
     "HUMAN",
     "SYSTEM"
    ],
    "last_sync_at": null
   },
   "operating_costs": {
    "status": "mostly_covered",
    "sources": [
     "AI_AGENT",
     "ANTHROPIC_API",
     "HUMAN",
     "OPENAI_API",
     "STRIPE_API"
    ],
    "last_sync_at": "2026-09-18T…Z"
   },
…
  1. Co widzi Owner w Approval Center (i decyzja: tu odrzucenie, żeby nic nie zostało).
{
 "status": 200,
 "data": {
  "id": "<id-40>",
  "owner_id": "<id-37>",
  "agent_id": "<id-38>",
  "action": "propose_ad_budget_change",
  "params": {
   "reason": "Google CPA 24 PLN vs Meta 37 PLN: shift 30 PLN/day",
   "current": {
    "currency": "PLN",
    "amount_minor": 10000
   },
   "platform": "google_ads",
   "proposed": {
    "currency": "PLN",
    "amount_minor": 13000
   },
   "business_id": "<business:tharan>"
  },
  "reason": "Google CPA 24 PLN vs Meta 37 PLN: shift 30 PLN/day",
  "amount_minor": 3000,
  "currency": "PLN",
  "business_id": "<business:tharan>",
  "personal": false,
  "status": "pending",
  "decided_by": null,
  "decided_at": null,
  "decision_note": null,
  "expires_at": "2026-09-25T…Z",
  "result_ref": null,
  "idempotency_key": "pb-marketing-ads-1",
  "created_at": "2026-09-18T…Z",
  "kind": "write"
 },
 "request_id": "req_<id-42>"
}

Owner próbuje zatwierdzić z Modify (spec §24: params_override zmienia tylko istniejące klucze params) i podnosi zmianę jeszcze wyżej niż zaproponował agent: ponowne sprawdzenie limitu (R-013) blokuje to jako 403, approval zostaje pending (nic nie jest wykonane, można spróbować ponownie albo odrzucić).

{
 "error": {
  "code": "limit_exceeded",
  "message": "the modified amount exceeds the agent's grant limit"
 }
}
{
 "status": 200,
 "data": {
  "id": "<id-40>",
  "owner_id": "<id-37>",
  "agent_id": "<id-38>",
  "action": "propose_ad_budget_change",
  "params": {
   "reason": "Google CPA 24 PLN vs Meta 37 PLN: shift 30 PLN/day",
   "current": {
    "currency": "PLN",
    "amount_minor": 10000
   },
   "platform": "google_ads",
   "proposed": {
    "currency": "PLN",
    "amount_minor": 13000
   },
   "business_id": "<business:tharan>"
  },
  "reason": "Google CPA 24 PLN vs Meta 37 PLN: shift 30 PLN/day",
  "amount_minor": 3000,
  "currency": "PLN",
  "business_id": "<business:tharan>",
  "personal": false,
  "status": "rejected",
  "decided_by": "<id-37>",
  "decided_at": "2026-09-18T…Z",
  "decision_note": "playbook: not now",
  "expires_at": "2026-09-25T…Z",
  "result_ref": null,
  "idempotency_key": "pb-marketing-ads-1",
  "created_at": "2026-09-18T…Z",
  "kind": "write"
 },
 "request_id": "req_<id-43>"
}

#Gdzie jest 202

Krok 4: zmiana 100 → 130 PLN/dzień to +30 %, a grant pozwala na ±10 %/dzień bez zgody. Wynik tool to pending_approval z approval_id; Owner widzi akcję, parametry, powód i (po wdrożeniu POST /v1/simulations) wpływ na forecast. Zmiana ≤ 10 % zostałaby wykonana od razu jako zapis planu (201) z automatycznie zatwierdzonym Approval w audycie.

#Czego agent NIE może

create_expense, reserve_budget, create_planned_expense (brak grantów, scope_denied), czytać Clothing/Klima ani personal, zmieniać budżetu powyżej limitów dziennych/miesięcznych (limit_exceeded, twarde 403), dotykać realnych kont reklamowych (MVP zapisuje tylko plan).