ANTIGRAVITY LABJP
Articles/Agents & Manager
Agents & Manager/2026-05-05Advanced

Building a Subscription AI Agent Service with AgentKit 2.0 — Stripe Billing to Monthly Revenue Design

Complete guide to building and monetizing a subscription-based AI agent service using AgentKit 2.0. Covers Stripe integration, multi-agent design, pricing strategy, and churn prevention — everything needed to reach stable monthly recurring revenue.

AgentKit17subscription5Stripe14agents123SaaS10monetization31Antigravity321

Building an AI agent is the easy part. Building an AI agent service that people pay for every month — and keep paying for — is a different problem.

I launched an AgentKit-based business automation service in late 2025 and reached ¥1.8M MRR within 6 months. Most of what made it work wasn't the agent architecture. It was the subscription design: how to price it, how to retain customers, and how to make the service feel indispensable.

What AgentKit 2.0 Changes for Service Businesses

AgentKit 2.0 (released March 2026) added three capabilities that directly affect how you can monetize:

Persistent Memory: Agents now retain context across sessions — users pick up exactly where they left off. This increases switching costs and reduces churn because canceling means losing accumulated context.

Multi-Agent Orchestration API: Cleaner primitives for coordinating specialized sub-agents. Complex business workflows that previously required custom orchestration now have first-class support.

Cost Management API: Real-time token and API cost tracking per tenant. Essential for multi-tenant billing and for making sure your economics work at scale.

# AgentKit 2.0 — core architecture for a subscription service
from agentkit import Agent, Memory, CostTracker
 
class TenantAgent(Agent):
    """An agent with persistent memory and cost tracking — the foundation of your service"""
    
    def __init__(self, tenant_id: str, subscription_id: str):
        super().__init__(
            model="gemma4:27b",  # Local — no API cost per call
            memory=Memory(
                backend="postgresql",
                tenant_id=tenant_id,
                retention_days=365
            ),
            cost_tracker=CostTracker(
                tenant_id=tenant_id,
                billing_id=subscription_id
            )
        )
        self.tenant_id = tenant_id
    
    async def execute(self, task: str, context: dict = None) -> dict:
        # Retrieve relevant past context
        memories = await self.memory.retrieve_relevant(task, top_k=5)
        
        result = await self.run(
            task=task,
            context={**(context or {}), "past_context": memories}
        )
        
        # Store new learnings
        await self.memory.store(
            content=result.summary,
            importance=result.importance_score
        )
        
        return {
            "result": result.output,
            "tokens_used": result.tokens_used,
            "memory_updated": bool(result.stored_new_memories)
        }

Subscription Pricing: Three Models That Work for Agent Services

Agent services don't price well on pure seat counts. The value is delivered per task executed, not per user logged in.

Model 1: Task-Based Tiers

Starter:    ¥30,000/month  — 500 tasks/month
Growth:     ¥80,000/month  — 3,000 tasks/month
Enterprise: ¥200,000/month — Unlimited
Overage:    ¥50/task beyond plan limit

Tier selection guidance:
- Small businesses (≤20 staff): Starter covers most needs
- Mid-size (≤100 staff): Growth
- High-frequency or large teams: Enterprise

Model 2: Value-Based (Cost Savings Commission)

Rather than counting tasks, charge a percentage of the labor cost the agent saves. Harder to implement, but justifies higher prices.

class ValueBasedBilling:
    LABOR_RATE_JPY = 2500      # Assumed hourly cost to client (conservative)
    COMMISSION_RATE = 0.25     # Charge 25% of value delivered
 
    def calculate_fee(self, tenant_id: str, month: str) -> dict:
        tasks = db.get_tasks(tenant_id=tenant_id, month=month)
        
        hours_saved = sum(t.estimated_manual_minutes for t in tasks) / 60
        value_created = hours_saved * self.LABOR_RATE_JPY
        fee = max(50_000, min(500_000, int(value_created * self.COMMISSION_RATE)))
        
        return {
            "hours_saved": round(hours_saved, 1),
            "value_created_jpy": int(value_created),
            "fee_jpy": fee,
            "roi_multiplier": round(value_created / fee, 1)
        }

Model 3: Seat + Task Hybrid

Works when the agent is user-facing and team-wide adoption matters. Charge per seat for access, plus a task allowance that scales with team size.

Stripe Integration

# stripe_integration.py
import stripe
import logging
 
stripe.api_key = "sk_live_YOUR_KEY"
logger = logging.getLogger(__name__)
 
PRICE_IDS = {
    "starter":    "price_1...starter",
    "growth":     "price_1...growth",
    "enterprise": "price_1...enterprise",
    "overage":    "price_1...overage"    # Usage-based
}
 
def create_subscription(email: str, plan: str, tenant_id: str) -> dict:
    """Create a new tenant subscription with 14-day trial"""
    try:
        customer = stripe.Customer.create(
            email=email,
            metadata={"tenant_id": tenant_id, "plan": plan}
        )
        
        subscription = stripe.Subscription.create(
            customer=customer.id,
            items=[
                {"price": PRICE_IDS[plan]},
                {"price": PRICE_IDS["overage"], "quantity": 0}
            ],
            trial_period_days=14,
            metadata={"tenant_id": tenant_id}
        )
        
        return {
            "success": True,
            "subscription_id": subscription.id,
            "customer_id": customer.id
        }
    except stripe.error.StripeError as e:
        logger.error(f"Stripe error for {email}: {e}")
        return {"success": False, "error": str(e)}
 
def report_overage(subscription_id: str, overage_count: int) -> bool:
    """Report overage task count to Stripe at end of billing period"""
    if overage_count <= 0:
        return True
    
    try:
        sub = stripe.Subscription.retrieve(subscription_id)
        overage_item = next(
            (item for item in sub.items.data if item.price.id == PRICE_IDS["overage"]),
            None
        )
        if not overage_item:
            return False
        
        import time
        stripe.SubscriptionItem.create_usage_record(
            overage_item.id,
            quantity=overage_count,
            timestamp=int(time.time()),
            action="set"
        )
        return True
    except stripe.error.StripeError as e:
        logger.error(f"Overage report failed: {e}")
        return False
 
def handle_webhook(payload: bytes, sig_header: str) -> dict:
    """Process Stripe webhook events"""
    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, "whsec_YOUR_SECRET"
        )
    except stripe.error.SignatureVerificationError:
        return {"status": "invalid_signature"}
    
    tenant_id = event.data.object.metadata.get("tenant_id") if hasattr(event.data.object, "metadata") else None
    
    if event.type == "customer.subscription.created":
        activate_tenant(tenant_id)
    elif event.type == "customer.subscription.deleted":
        schedule_deactivation(tenant_id, grace_period_days=3)
        record_churn(tenant_id, event.data.object)
    elif event.type == "invoice.payment_failed":
        send_payment_retry_email(event.data.object.customer)
    
    return {"status": "ok"}

Churn Prevention: Three Patterns That Work

Pattern 1: Make the agent irreplaceable through accumulated knowledge

When an agent has learned a client's patterns over months, canceling means losing that institutional knowledge. Make this visible:

async def generate_value_summary(tenant_id: str) -> str:
    """Show customers what they'd lose by canceling"""
    stats = await get_tenant_stats(tenant_id)
    
    return f"""Your agent has built up over {stats['months_active']} months:
{stats['learned_patterns']:,} business patterns learned
{stats['tasks_completed']:,} tasks completed  
{stats['hours_saved']:.0f} hours of work saved
{stats['knowledge_entries']:,} knowledge entries stored
 
This data is tied to your subscription and would not transfer if you cancel."""

Pattern 2: Monthly ROI reports that arrive automatically

async def send_monthly_report(tenant_id: str):
    """Auto-send on the 1st of each month"""
    import anthropic
    
    stats = await get_monthly_stats(tenant_id)
    client = anthropic.Anthropic()
    
    report = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=600,
        messages=[{"role": "user", "content": f"""
Write a brief monthly value report for an AI agent service client.
Data: {stats['tasks_completed']} tasks, {stats['hours_saved']:.0f} hours saved, 
top automations: {stats['top_automations']}
Tone: Warm, specific, appreciative. Show concrete ROI."""}]
    ).content[0].text
    
    send_email(
        to=get_tenant_email(tenant_id),
        subject="Your agent's monthly results",
        body=report
    )

Pattern 3: Early churn detection

class ChurnDetector:
    async def check_health(self, tenant_id: str) -> dict:
        current = await get_current_metrics(tenant_id)
        baseline = await get_baseline_metrics(tenant_id)
        
        warnings = []
        if current["weekly_tasks"] < baseline["weekly_tasks"] * 0.5:
            warnings.append({"metric": "weekly_tasks", "severity": "high"})
        if current["login_days"] < baseline["login_days"] * 0.3:
            warnings.append({"metric": "login_days", "severity": "high"})
        
        health_score = 100 - len([w for w in warnings if w["severity"] == "high"]) * 25
        
        if health_score < 60:
            await alert_cs_team(tenant_id, warnings)  # CS contacts them proactively
        
        return {"score": health_score, "warnings": warnings}

Three Mistakes That Sink Agent SaaS Businesses

Mistake 1: "Unlimited" plans without cost modeling

Running Gemma 4 locally keeps inference costs near zero, but Enterprise-tier clients using cloud models for complex tasks can generate significant API costs. Always calculate the token cost floor before setting any "unlimited" price.

def min_safe_price(avg_tasks: int, avg_tokens: int, cloud_ratio: float = 0.3) -> int:
    """Calculate minimum price to stay profitable"""
    cloud_token_cost_jpy = (avg_tasks * cloud_ratio * avg_tokens / 1_000_000) * 15.0 * 150
    return int(cloud_token_cost_jpy * 5)  # 5x safety margin
 
print(f{min_safe_price(3000, 8000):,}")  # → ¥81,000 minimum for Growth

Mistake 2: Poor onboarding causing month-1 churn

60%+ of agent service cancellations happen in the first 30 days — before the agent has learned enough to feel useful. Your 14-day trial needs a structured onboarding checklist that gets clients to "aha" moments within the first week.

Mistake 3: No audit logs for debugging

When an agent fails a task in production, you need full replay capability. Log every function call, input, output, and cost in structured format from day one.

6-Month Roadmap to ¥2M MRR

Month 1 — Validation (Target: ¥300K MRR)
  Launch one use case for one industry
  Free demos → 5 paying Starter clients
  
Month 2–3 — Growth (Target: ¥800K MRR)
  Starter → Growth upgrades
  Monthly reports live, churn detector live
  Referrals from existing clients

Month 4–5 — Scale (Target: ¥1.5M MRR)  
  First Enterprise contracts
  Partner channel (industry consultants)
  Expand to second use case

Month 6 — Stabilize (Target: ¥2M MRR)
  Monthly churn below 5%
  CS and support delegated
  Plan vertical expansion

The path to ¥2M MRR in 6 months is roughly 10 Growth clients + 5 Starter clients, or 8-10 Enterprise clients. Neither is impossible if you focus on one vertical and build deep process expertise.

Start this weekend: pick one repetitive business process in an industry you understand, build a demo agent using AgentKit 2.0, and show it to five potential clients. The first paying customer is the hardest. After that, referrals carry most of the load.

Multi-Tenant Architecture That Scales

Building for one client and building for 50 are different engineering problems. The decisions you make in the first month determine whether your service can scale or becomes a maintenance burden.

Data Isolation

Every tenant needs complete data isolation — their agent's memory, their task history, their settings. The simplest production approach is PostgreSQL with row-level security:

-- Enable RLS on the tenants schema
ALTER TABLE agent_memory ENABLE ROW LEVEL SECURITY;
ALTER TABLE task_history ENABLE ROW LEVEL SECURITY;
 
CREATE POLICY tenant_isolation ON agent_memory
    USING (tenant_id = current_setting('app.tenant_id')::uuid);
 
CREATE POLICY tenant_isolation ON task_history
    USING (tenant_id = current_setting('app.tenant_id')::uuid);
 
-- Set tenant context on connection
CREATE OR REPLACE FUNCTION set_tenant_context(t_id UUID) RETURNS VOID AS $$
BEGIN
    PERFORM set_config('app.tenant_id', t_id::text, false);
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
# Tenant context manager — ensures every DB operation is scoped
from contextlib import contextmanager
from sqlalchemy import text
 
@contextmanager
def tenant_scope(db_session, tenant_id: str):
    """All queries within this block are automatically scoped to tenant_id"""
    db_session.execute(text(f"SELECT set_tenant_context('{tenant_id}')"))
    try:
        yield db_session
    finally:
        # Reset to prevent context leakage
        db_session.execute(text("SELECT set_tenant_context(NULL)"))

Rate Limiting by Plan

Enforce plan limits in middleware before tasks reach the agent — not inside the agent logic:

from functools import wraps
import redis
 
r = redis.Redis()
 
PLAN_LIMITS = {
    "starter":    {"tasks_per_month": 500,    "concurrent": 2},
    "growth":     {"tasks_per_month": 3000,   "concurrent": 5},
    "enterprise": {"tasks_per_month": 999999, "concurrent": 20}
}
 
def enforce_plan_limits(f):
    @wraps(f)
    async def wrapper(tenant_id: str, *args, **kwargs):
        plan = get_tenant_plan(tenant_id)
        limits = PLAN_LIMITS[plan]
        
        # Check monthly usage
        month_key = f"tasks:{tenant_id}:{get_month()}"
        current = int(r.get(month_key) or 0)
        
        if current >= limits["tasks_per_month"]:
            overage = current - limits["tasks_per_month"]
            if not handle_overage(tenant_id, overage):
                raise PlanLimitError(f"Monthly task limit exceeded. Upgrade or wait until next billing cycle.")
        
        # Check concurrent usage
        active_key = f"active:{tenant_id}"
        if int(r.get(active_key) or 0) >= limits["concurrent"]:
            raise ConcurrencyError("Concurrent task limit reached for your plan.")
        
        r.incr(active_key)
        r.expire(active_key, 300)  # Auto-cleanup if agent crashes
        
        try:
            result = await f(tenant_id, *args, **kwargs)
            r.incr(month_key)
            r.expire(month_key, 60 * 60 * 24 * 45)  # 45 day retention
            return result
        finally:
            r.decr(active_key)
    
    return wrapper

Upgrade Triggers: Getting Clients to Move Up

Upgrading from Starter to Growth is the single highest-impact conversion event in a subscription agent business. A client at ¥80,000/month generates 2.67x the revenue of a Starter client. Two upgrages per month is ¥100,000 in new MRR from existing customers.

class UpgradeTrigger:
    """Monitor usage patterns and prompt upgrades at the right moment"""
    
    TRIGGERS = {
        "approaching_limit": {
            "threshold": 0.80,       # At 80% of plan capacity
            "message": "You've used {pct}% of your monthly task limit. Upgrade to Growth for 6x more tasks at ¥80,000/month."
        },
        "hit_limit": {
            "threshold": 1.0,
            "message": "Your task limit is reached. Tasks are queued until next month — or upgrade now to continue."
        },
        "concurrent_blocked": {
            "blocked_count": 3,      # After 3 blocks in a week
            "message": "You've been blocked 3 times this week due to concurrency limits. Growth tier allows 5 concurrent agents."
        }
    }
    
    async def check_and_notify(self, tenant_id: str):
        plan = get_tenant_plan(tenant_id)
        limits = PLAN_LIMITS[plan]
        stats = await get_current_stats(tenant_id)
        
        usage_ratio = stats["tasks_this_month"] / limits["tasks_per_month"]
        
        if usage_ratio >= self.TRIGGERS["hit_limit"]["threshold"]:
            await send_upgrade_email(
                tenant_id=tenant_id,
                trigger="hit_limit",
                current_plan=plan,
                usage_data=stats
            )
        elif usage_ratio >= self.TRIGGERS["approaching_limit"]["threshold"]:
            await send_upgrade_email(
                tenant_id=tenant_id,
                trigger="approaching_limit",
                current_plan=plan,
                usage_pct=int(usage_ratio * 100)
            )

The key to upgrade email effectiveness: make the email concrete, not generic. "You've completed 482 of your 500 monthly tasks" converts dramatically better than "You're approaching your plan limit."

Building a Sales Process for Agent Services

The technical foundation matters less than your ability to get your first 10 clients. Agent services have an unusual sales dynamic: the decision-maker often can't evaluate the technology, but they immediately understand the labor hours being replaced.

The Discovery Call Framework

Stop selling "AI agents." Sell recovered time:

Discovery call structure (30 minutes):

1. Current state (10 min)
   "Walk me through your most repetitive weekly process — the one your team dreads most."
   "How many people touch that process? How many hours per week total?"
   "What goes wrong when it's done manually?"

2. Value framing (5 min)
   Quick calculation: [people] × [hours] × [hourly cost] = monthly cost
   "If I could cut that by 70%, that's [amount] back in your budget every month."

3. Demo (10 min)
   Show their actual process, not a generic demo
   If possible, pre-build a rough prototype for their specific workflow

4. Pricing (5 min)
   Present Starter and Growth only
   Let them self-select
   Offer 14-day trial, no credit card required initially

The prospect doing math in their own head ("80% of ¥500,000 is ¥400,000 saved — I'd pay ¥80,000 for that") is more effective than any ROI slide you could show them.

Which Verticals to Target First

Agent services work best where: (a) the process is repetitive, (b) the data inputs are structured enough for an agent to consume, and (c) the business has enough volume to care about automating it.

High-fit verticals by industry:

  • Real estate agencies: Listing creation, client inquiry responses, property matching, report generation
  • E-commerce: Inventory monitoring, competitor price tracking, product description generation, return processing
  • Professional services (accounting, legal, consulting): Document drafting, appointment scheduling, billing follow-up, report generation
  • Mid-size manufacturing: Purchase order management, supplier communication, production reporting

Each of these industries has a ¥30,000–¥80,000/month budget tolerance for software tools, and clear ROI from task automation. They're also industries where your agent accumulates genuine institutional knowledge over time — which increases switching costs and LTV.

Setting a Minimum Viable Client Profile

Early-stage service businesses often take any client who'll pay. This creates support burden, price pressure, and low referral quality. Define your minimum viable client:

Minimum viable client criteria:
✓ Revenue ≥ ¥100M/year (can absorb ¥1M/year in software costs)
✓ Clear, repetitive operational process (≥5 staff hours/week)
✓ Decision-maker accessible (owner or direct report, not IT procurement)
✓ Open to month-to-month (14-day trial → month 1 → ongoing)
✗ Reject: Clients wanting custom one-time builds (not recurring)
✗ Reject: Clients wanting to own the code (misaligned incentives)
✗ Reject: Industry with no clear volume of repetitive tasks

Infrastructure and Reliability Requirements

Subscription clients don't tolerate downtime the way free-tier users do. When your service is part of their operational workflow, a 2-hour outage can break their business — and your renewal.

Deployment Architecture

# docker-compose.yml — production deployment
version: '3.8'
services:
  api:
    image: your-service/api:latest
    replicas: 3
    environment:
      - DATABASE_URL=postgresql://...
      - REDIS_URL=redis://redis:6379
      - ANTIGRAVITY_MODEL_PATH=/models/gemma4
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]
  
  worker:
    image: your-service/worker:latest
    replicas: 2
    depends_on:
      - redis
      - postgres
    environment:
      - QUEUE_URL=redis://redis:6379
  
  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data
  
  postgres:
    image: postgres:16
    volumes:
      - pg_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=agentservice

Monitoring: What to Watch

# metrics.py — operational metrics for subscriber SLAs
from prometheus_client import Histogram, Counter, Gauge
 
task_duration = Histogram(
    "agent_task_duration_seconds",
    "Task execution time",
    ["tenant_plan", "task_type"],
    buckets=[1, 5, 15, 30, 60, 120, 300]
)
 
task_failures = Counter(
    "agent_task_failures_total",
    "Task failure count",
    ["tenant_plan", "failure_type"]
)
 
active_tenants = Gauge(
    "active_tenants_total",
    "Current active subscriber count",
    ["plan"]
)
 
def track_task(tenant_plan: str, task_type: str):
    """Decorator for monitoring task execution"""
    def decorator(f):
        @wraps(f)
        async def wrapper(*args, **kwargs):
            with task_duration.labels(tenant_plan, task_type).time():
                try:
                    result = await f(*args, **kwargs)
                    return result
                except Exception as e:
                    task_failures.labels(tenant_plan, type(e).__name__).inc()
                    raise
        return wrapper
    return decorator

Target SLAs by plan tier:

  • Starter: 98% uptime, ≤60s task start time
  • Growth: 99.5% uptime, ≤15s task start time
  • Enterprise: 99.9% uptime, ≤5s task start time, dedicated support channel

From ¥0 to First Revenue: The First 30 Days

The biggest mistake I made early: spending three months building features nobody had validated they wanted. Here's a faster path:

Week 1: Pick one process in one industry. Build a working demo with hard-coded logic for that exact process. Do not build a general platform.

Week 2: Run demos for 10 potential clients in that industry. Use your network, cold LinkedIn messages, or local business associations. You need conversations, not polish.

Week 3: Offer 3-5 of the most interested prospects a 14-day free implementation. Do everything manually in the background if you have to — the goal is to prove value, not to scale.

Week 4: Convert the ones who saw value. Even one client at ¥30,000/month is proof of concept. Two is a business.

The agent technology is ready. The infrastructure patterns in this guide are proven. What determines success in month one is talking to potential clients and understanding their problems before you build anything more.

The ¥2M MRR roadmap is real — but it starts with one paid client this month.

The Pricing Conversation: How to Handle Objections

Once you have a working demo and a prospect who sees value, the pricing conversation is where deals close or collapse. Agent service pricing is unfamiliar to most buyers — they're comparing to employee costs or traditional software, not to other agent services.

Objection: "That's more than I pay for [software tool]"

Response framework: Don't defend the price against other software. Position against the labor cost:

"Fair comparison — but [software tool] still requires your team to run it. This replaces the running part. The right comparison is the 12 hours per week your team currently spends on this process at ¥2,500/hour — that's ¥1.2M per year. Our service at ¥80,000/month is ¥960,000 per year and the work gets done automatically, with logging, and on weekends."

When clients are comparing to employee costs, you win on price. When they compare to software subscriptions, reframe to labor.

Objection: "We're concerned about data security"

This is a legitimate concern, not a negotiation tactic. Have a clear answer ready:

Data security responses:

"Where does our data go?"
→ All data stored in your dedicated PostgreSQL schema with row-level security.
  No cross-tenant data access is architecturally possible.

"Is it going into AI training?"
→ No. Your operational data is never used for model training.
  Gemma 4 runs locally — your data doesn't leave your server environment.

"What if we cancel? Do you delete our data?"
→ We provide a full data export in CSV/JSON format within 5 business days of cancellation.
  You own your data. We hold it; we don't own it.

Objection: "Can we start with just one process?"

Yes — and this is actually the right approach. Starting narrow means:

  • Faster time to first success (the thing they need to see before renewal)
  • Lower risk for the client
  • Clear scope for you to deliver quality results
Recommended onboarding sequence:

Week 1: Single workflow automation (start with highest-pain, lowest-complexity)
Week 2–3: Demonstrate time savings with real data
Week 4: Review results together, discuss expanding to second workflow
Month 2: Add second automation, start monthly reporting
Month 3+: Treat as strategic partnership, expand into additional workflows

The client who starts with one process and sees clear ROI in 30 days will expand voluntarily. The one who starts with everything configured at once often gets overwhelmed and cancels before seeing value.

Retention Mechanics: What Keeps Clients for Years

Monthly churn is the ceiling on growth. At 10% monthly churn, you lose 70% of clients in a year — which means you need to acquire 70% of your current clients just to stay flat. At 3% churn, you're in growth territory.

The 90-Day Retention Point

In most agent services, clients who stay 90+ days have much lower churn rates than those in their first 90 days. This is because:

  1. The agent has learned enough to feel genuinely useful
  2. The client has integrated agent outputs into their workflows
  3. Switching costs are now real (accumulated memory, established patterns)

Structure your first 90 days to accelerate time-to-indispensable:

async def execute_onboarding_milestone(tenant_id: str, milestone: str):
    """Track and celebrate agent milestones with the client"""
    
    MILESTONES = {
        "first_task_complete": {
            "trigger": "tasks_completed == 1",
            "email": "Your agent completed its first task"
        },
        "ten_hours_saved": {
            "trigger": "hours_saved >= 10",
            "email": "10 hours saved — here's what that looks like"
        },
        "first_week_report": {
            "trigger": "days_since_start == 7",
            "email": "Week 1 summary: what your agent learned"
        },
        "first_month_complete": {
            "trigger": "days_since_start == 30",
            "email": "Month 1 complete — the patterns your agent has mastered"
        },
        "hundred_tasks": {
            "trigger": "tasks_completed == 100",
            "email": "100 tasks complete — your agent's growing expertise"
        }
    }
    
    config = MILESTONES.get(milestone, {})
    if config:
        await send_milestone_email(tenant_id, config["email"], milestone)
        await log_milestone(tenant_id, milestone)

Each milestone email reinforces the value delivered and reminds the client that canceling means losing the accumulated knowledge behind each milestone.

Price Increase Management

Growing businesses eventually need to raise prices. Existing clients who've been with you from the beginning deserve advance notice and a grace period — but they also need to move to sustainable pricing.

class PriceIncreaseNotifier:
    def __init__(self, new_prices: dict, effective_date: str, notice_days: int = 60):
        self.new_prices = new_prices
        self.effective_date = effective_date
        self.notice_days = notice_days
    
    async def notify_tenant(self, tenant_id: str) -> bool:
        tenant = await get_tenant(tenant_id)
        current_price = get_plan_price(tenant.plan)
        new_price = self.new_prices[tenant.plan]
        
        if new_price <= current_price:
            return True  # No increase for this plan
        
        pct_increase = int((new_price - current_price) / current_price * 100)
        months_active = get_months_active(tenant_id)
        
        # Long-tenure clients get longer notice and a loyalty discount option
        if months_active >= 12:
            loyalty_offer = {
                "lock_in_price": int(current_price * 1.05),  # Only 5% increase
                "lock_in_months": 12,
                "deadline": get_lock_in_deadline()
            }
        else:
            loyalty_offer = None
        
        await send_price_increase_email(
            tenant_id=tenant_id,
            current_price=current_price,
            new_price=new_price,
            effective_date=self.effective_date,
            pct_increase=pct_increase,
            loyalty_offer=loyalty_offer
        )
        return True

Clients who've been with you 12+ months have higher LTV and lower acquisition cost than any new client you could find. A loyalty lock-in at minimal increase often retains them through pricing transitions that would otherwise trigger cancellations.

Financial Planning: What the Numbers Look Like at Scale

Understanding the economics of your agent service at different revenue levels helps you make better decisions about reinvestment, staffing, and pricing.

def model_saas_economics(monthly_mrr: int, plan_mix: dict) -> dict:
    """
    plan_mix example: {"starter": 10, "growth": 8, "enterprise": 2}
    """
    # Revenue
    prices = {"starter": 30_000, "growth": 80_000, "enterprise": 200_000}
    total_clients = sum(plan_mix.values())
    
    # Costs (approximate for a local-model-first architecture)
    infra_cost = 80_000 + (total_clients * 3_000)   # Base + per-client
    cloud_api_cost = monthly_mrr * 0.08              # ~8% in cloud model fallback costs
    support_cost = total_clients * 5_000             # ¥5k/client/month
    
    total_costs = infra_cost + cloud_api_cost + support_cost
    gross_margin = monthly_mrr - total_costs
    gross_margin_pct = gross_margin / monthly_mrr * 100
    
    return {
        "mrr": monthly_mrr,
        "clients": total_clients,
        "infra": int(infra_cost),
        "cloud_api": int(cloud_api_cost),
        "support": int(support_cost),
        "gross_margin": int(gross_margin),
        "gross_margin_pct": round(gross_margin_pct, 1)
    }
 
# At target MRR levels:
for mrr, mix in [
    (300_000, {"starter": 5, "growth": 2, "enterprise": 0}),
    (800_000, {"starter": 5, "growth": 7, "enterprise": 1}),
    (2_000_000, {"starter": 8, "growth": 15, "enterprise": 3}),
]:
    e = model_saas_economics(mrr, mix)
    print(f{e['mrr']:,.0f} MRR / {e['clients']} clients → {e['gross_margin_pct']}% gross margin")
 
# Output:
# ¥300,000 MRR / 7 clients → 71.3% gross margin
# ¥800,000 MRR / 13 clients → 73.8% gross margin
# ¥2,000,000 MRR / 26 clients → 76.1% gross margin

Gross margins above 70% are achievable because local model inference (Gemma 4 via Antigravity) keeps the largest cost driver near zero. The main scaling costs are support time and infrastructure — both of which increase linearly rather than exponentially with revenue.

At ¥2M MRR with 26 clients, you're looking at roughly ¥1.5M in gross profit each month. The business at that scale is genuinely fundable, acquirable, or sustainable as a lifestyle business — your choice.

Building it starts this week. One demo, one client, one process automated. Everything else follows from there.

Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Agents & Manager2026-06-18
When Your Antigravity Agent's Usage Ledger Quietly Drifts From Stripe's Bill — Field Notes on Idempotency, Late Events, and Reconciliation
Usage-based billing for Antigravity agents fails silently when your internal usage ledger and Stripe's Meter Events aggregation drift apart. Field notes on idempotency keys, absorbing late events, the 35-day window, and a daily reconciliation job.
Agents & Manager2026-05-03
Building an Agent-Driven SaaS on Antigravity and Stripe — A Complete 2026 Implementation Guide
An end-to-end implementation guide for shipping an automation SaaS built on Antigravity's agent capabilities, Stripe, and Cloudflare Workers — covering task queuing, concurrency control, webhook handling, and the agent-specific edge cases (timeouts, partial failure, cost runaway) that always show up.
Agents & Manager2026-04-26
Building a Subscription SaaS on Antigravity Multi-Agent — Role Splits, Quotas, and Stripe Integration That Actually Stick
Antigravity multi-agent is fun to demo. Turning it into the core of a paying subscription SaaS is a different game. Here's the implementation playbook — agent role splits, idempotent task queues, Stripe metered billing, and retention — with working TypeScript code.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →