# API Integration Guide

This guide covers everything you need to integrate your application with SOMA AMI, from initial setup to production deployment.

## Table of Contents

1. [Quick Start](#quick-start)
2. [Project Structure](#project-structure)
3. [EMU Registration](#emu-registration)
4. [Building ATOMs (Best Practices)](#building-atoms-best-practices)
5. [CLI Tool Reference](#cli-tool-reference)
6. [Integration Workflows](#integration-workflows)
7. [Testing & Validation](#testing--validation)

---

## Quick Start

Get up and running in 5 minutes.

### 1. Install the SDK

```bash
# Using pip
pip install memrail

# Using uv (recommended)
uv add memrail

# From source
cd sdk && pip install -e .
```

### 2. Configure Credentials

Create a `.env` file from the template:

```bash
cp .env.example .env
```

Edit `.env` with your credentials:

```bash
AMI_API_KEY=your-api-key-here
AMI_ORG=your-org-slug
AMI_TEAM=your-team-slug
AMI_WORKSPACE=production
AMI_PROJECT=default
```

### 3. Register Your First EMU

Use the IaC workflow to manage EMUs as code:

```bash
# Pull current EMU state from API
memrail emu-pull ./emus/ -w production -p my-project

# Edit emus/emus.jsonl (one JSON object per line)

# Preview changes (like terraform plan)
memrail emu-plan ./emus/

# Apply changes to API
memrail emu-apply ./emus/ --yes
```

### 4. Decide and Handle Response

```python
from memrail import AsyncAMIClient
from memrail.atoms import state, tag

async with AsyncAMIClient() as client:
    # Build context atoms and invoke decision engine
    response = await client.decide(
        context=[
            state("user.id", "U-123"),
            state("user.tier", "premium"),
            tag("intent", "support_request"),
        ],
        decision_point="triage",
        trace=True
    )

    # Handle selected EMUs
    for selection in response.selected:
        print(f"Selected: {selection.emu_key} (score: {selection.score})")

        if selection.action:
            # Execute the action
            await handle_action(selection.action)

            # Acknowledge completion
            await client.ack(
                activation_id=selection.activation_id,
                status="acknowledged"
            )
```

---

## Project Structure

Organize your EMUs using a project-based directory structure.

### Recommended Layout

```
your-repo/
├── emus/                        # EMU definitions (IaC)
│   ├── emus.jsonl              # One EMU per line (managed by memrail emu-pull/apply)
│   └── emus.lock.jsonl         # Lock file (auto-generated by emu-apply)
├── src/                         # Your application code
│   └── ...
├── .env                         # Credentials (git-ignored)
├── .env.example                 # Credential template
└── pyproject.toml
```

### IaC Workflow

EMUs are managed as code using a Terraform-like workflow:

```bash
# Pull current EMUs from API into local JSONL
memrail emu-pull ./emus/ -w production -p my-project

# Edit emus/emus.jsonl — one JSON object per line
# Preview what would change (like terraform plan)
memrail emu-plan ./emus/

# Apply changes to the API
memrail emu-apply ./emus/ --yes
```

### EMU File Format (JSONL)

EMUs are stored as one JSON object per line in `emus.jsonl`:

```jsonl
{"emu_key": "support.vip_escalation", "trigger": "state.customer.tier == \"vip\"", "action": {"type": "tool_call", "intent": "ESCALATE", "tool": {"tool_id": "zendesk_escalator"}}, "policy": {"mode": "auto", "priority": 9}}
{"emu_key": "onboarding.welcome_email", "trigger": "state.user.tier == \"premium\"", "action": {"type": "tool_call", "intent": "SEND_WELCOME", "tool": {"tool_id": "mailer"}}, "policy": {"mode": "auto", "priority": 7}}
```

---

## EMU Registration

### Programmatic Registration

Use the SDK to register EMUs directly:

```python
from memrail import AsyncAMIClient

async with AsyncAMIClient() as client:
    response = await client.register_emu(
        emu_key="support.vip_escalation",
        trigger='state.customer.tier == "vip" AND state.ticket.priority >= "high"',
        action={
            "type": "tool_call",
            "intent": "Escalate to VIP team",
            "tool": {
                "tool_id": "zendesk_escalator",
                "version": "2.1.0",
                "args": {"queue": "vip-support"}
            }
        },
        policy={
            "mode": "auto",
            "priority": 9,
            "cooldown": {"seconds": 7200, "gate": "activation"},
            "exclusion_groups": ["escalation_actions"]
        },
        expected_utility=0.95,
        confidence=0.88,
        intent="Ensure VIP customers receive priority support",
        state="draft"  # Start in draft, promote to active later
    )

    print(f"Registered EMU: {response['emu_id']}")
```

### Updating Existing EMUs

Use `update_emu()` to modify an existing EMU in-place (preserves version history):

```python
from memrail import AsyncAMIClient

async with AsyncAMIClient() as client:
    response = await client.update_emu(
        emu_key="support.vip_escalation",
        trigger='state.customer.tier == "vip" AND state.ticket.priority >= "critical"',  # Modified
        expected_utility=0.95,
        confidence=0.90,
        policy={
            "mode": "auto",
            "priority": 10,  # Increased priority
            "cooldown": {"seconds": 3600, "gate": "activation"}
        },
        action={
            "type": "tool_call",
            "intent": "Escalate to VIP team",
            "tool": {"tool_id": "zendesk_escalator", "version": "2.2.0"}
        },
        workspace="production",
        project="support"
    )

    print(f"Updated: {response.get('status')} - {response.get('message')}")
```

**API Endpoint**: `PUT /v1/workspaces/{workspace}/projects/{project}/emus/{emu_key}`

### CLI Management (IaC Workflow)

Use the Terraform-like IaC workflow for managing EMUs:

```bash
# Pull current EMUs from API
memrail emu-pull ./emus/ -w production -p my-project

# Edit emus/emus.jsonl locally

# Preview changes (diff against remote)
memrail emu-plan ./emus/

# Apply changes to API
memrail emu-apply ./emus/ --yes
```

### EMU Lifecycle States

| State | Description | When to Use |
|-------|-------------|-------------|
| `draft` | Not evaluated | Initial development |
| `shadow` | Evaluated but not executed | Testing triggers without side effects |
| `canary` | Limited rollout | Gradual production rollout |
| `active` | Full production | Validated and ready |
| `archived` | Deactivated | End of life |

Progression: `draft` → `shadow` → `canary` → `active` → `archived`

### Policy Mode Behavior

The `policy.mode` field controls how actions are executed:

| action.type | mode = auto | mode = require_human | mode = advisory |
|-------------|-------------|----------------------|-----------------|
| `tool_call` | Execute immediately | Create approval item | Log suggestion only |
| `decision_prompt` | Emit prompt | *(mode ignored)* | *(mode ignored)* |
| `route` | Apply route | *(normalizes to auto)* | *(normalizes to auto)* |
| `context_directive` | Apply directive | *(normalizes to auto)* | *(normalizes to auto)* |

**When to use each mode:**
- **`auto`**: Fully automated execution (default)
- **`require_human`**: For `tool_call` actions needing human approval before execution
- **`advisory`**: For `tool_call` actions where you want to record suggestions without executing

---

## Building ATOMs (Best Practices)

ATOMs are the facts that EMU triggers evaluate against.

### Use StateObject for Complex Objects (Recommended)

The `StateObject` builder converts dictionaries to validated state atoms:

```python
from memrail.builders import StateObject

# RECOMMENDED: Use StateObject for dict conversion
user_data = {
    "id": "U-123",
    "tier": "premium",
    "is_active": True,
    "login_count": 42
}

user = StateObject("user", user_data)
atoms = user.to_atoms()

# Generates:
# [
#     state("user.id", "U-123"),
#     state("user.tier", "premium"),
#     state("user.is_active", True),
#     state("user.login_count", 42),
# ]
```

Benefits:
- Automatic validation of key formats
- Type checking for values
- Consistent naming conventions
- Easier to maintain

### Manual Atom Building (Simple Cases)

For simple cases with a few atoms:

```python
from memrail.atoms import state, tag, event
from datetime import datetime, timezone

atoms = [
    # State atoms (key-value facts)
    state("user.tier", "premium"),
    state("ticket.priority", 3),

    # Tag atoms (categorical metadata)
    tag("sentiment", "negative", source="ml"),
    tag("intent", "upgrade_request", source="ml"),

    # Event atoms (timestamped actions)
    event(
        "user.login.success",
        ts=datetime.now(timezone.utc),
        subject_anchor=("user", "U-123")
    ),
]
```

### Atom Type Reference

| Type | Format | Example | Use Case |
|------|--------|---------|----------|
| State | `state(key, value)` | `state("user.tier", "premium")` | Facts about entities |
| Tag | `tag(kind, value)` | `tag("intent", "escalation")` | ML classifications |
| Event | `event(topic, ts=...)` | `event("user.login.success", ts=now)` | User/system actions |

### Key Format Rules

- **State keys**: 2-7 dot-separated parts, lowercase + underscores
  - Valid: `user.tier`, `account.billing.status`
  - Invalid: `User.Tier`, `a.b.c.d.e.f.g.h` (too deep)

- **Tag kinds**: ≤64 characters, lowercase

- **Event topics**: 3-4 dot-separated parts (Subject.Verb.Object)
  - Valid: `user.login.success`, `agent.sent.welcome_email`

---

## CLI Tool Reference

### IaC Commands

#### `memrail emu-pull`

Pull current EMUs from API into local JSONL:

```bash
memrail emu-pull ./emus/ -w WORKSPACE -p PROJECT [OPTIONS]

Options:
  -w, --workspace TEXT   Workspace slug
  -p, --project TEXT     Project slug
  --force                Overwrite local changes
```

#### `memrail emu-plan`

Preview changes between local JSONL and remote API (like `terraform plan`):

```bash
memrail emu-plan ./emus/ [OPTIONS]

Options:
  --json                 Output as JSON (for CI pipelines)
```

#### `memrail emu-apply`

Apply local JSONL changes to the API (like `terraform apply`):

```bash
memrail emu-apply ./emus/ [OPTIONS]

Options:
  --yes                  Skip confirmation prompt
```

---

## Integration Workflows

### Customer Support Integration

```python
from memrail import AsyncAMIClient
from memrail.builders import StateObject
from memrail.atoms import tag, event
from datetime import datetime, timezone

async def handle_support_ticket(ticket: dict, customer: dict, ml_analysis: dict):
    async with AsyncAMIClient() as client:
        # Build context from ticket data
        ticket_state = StateObject("ticket", {
            "id": ticket["id"],
            "status": ticket["status"],
            "priority": ticket["priority"],
            "sla_remaining_minutes": ticket["sla_minutes_left"],
        })

        customer_state = StateObject("customer", {
            "id": customer["id"],
            "tier": customer["tier"],
            "lifetime_value": customer["ltv"],
        })

        # Add ML-derived tags
        tags = [
            tag("sentiment", ml_analysis["sentiment"], source="ml"),
            tag("intent", ml_analysis["intent"], source="ml"),
        ]

        # Combine all atoms
        atoms = ticket_state.to_atoms() + customer_state.to_atoms() + tags

        # Invoke decision engine
        response = await client.decide(context=atoms, decision_point="triage", trace=True)

        # Execute selected actions
        for selection in response.selected:
            if selection.action["type"] == "tool_call":
                await execute_tool(selection.action["tool"])
                await client.ack(activation_id=selection.activation_id, status="acknowledged")
            elif selection.action["type"] == "route":
                await route_ticket(ticket["id"], selection.action["route"])
                await client.ack(activation_id=selection.activation_id, status="acknowledged")
```

### Event-Driven Integration

```python
from memrail import AsyncAMIClient
from memrail.atoms import event
from datetime import datetime, timezone

async def on_user_action(action_type: str, user_id: str, metadata: dict):
    """Called when a user performs an action."""
    async with AsyncAMIClient() as client:
        # Emit the event
        topic = f"user.{action_type}.{metadata.get('object', 'item')}"

        await client.emit_event(
        event(
            topic,
            ts=datetime.now(timezone.utc),
            subject_anchor=("user", user_id),
            attributes=metadata
        )
    )
```

---

## Testing & Validation

### Local Validation

Always preview changes before applying:

```bash
# Preview what would change (like terraform plan)
memrail emu-plan ./emus/

# Preview in JSON format (for CI pipelines)
memrail emu-plan ./emus/ --json
```

### Shadow Mode Deployment

Deploy EMUs in shadow mode to test triggers without executing actions:

```python
# In your EMU definition
{
    "emu_key": "support.new_feature",
    "state": "shadow",  # Evaluated but not executed
    ...
}
```

### Trace Debugging

Enable tracing to understand EMU evaluation:

```python
async with AsyncAMIClient() as client:
    response = await client.decide(context=context, trace=True)

    if response.trace:
        print(f"Candidates evaluated: {len(response.trace['candidates'])}")
        for candidate in response.trace['candidates']:
            print(f"  {candidate['emu_key']}: {candidate['matched']}")
```

### Canary Rollouts

Gradually roll out new EMUs:

1. Deploy with `state: "shadow"` - Monitor trigger matches
2. Promote to `state: "canary"` - Execute for subset of traffic
3. Promote to `state: "active"` - Full production

---

## Environment Variables Reference

| Variable | Required | Description |
|----------|----------|-------------|
| `AMI_API_KEY` | Yes | API authentication key |
| `AMI_BASE_URL` | No | API endpoint (default: https://api.memrail.com) |
| `AMI_ORG` | Yes | Organization slug |
| `AMI_TEAM` | Yes | Team slug |
| `AMI_WORKSPACE` | No | Default workspace slug |
| `AMI_PROJECT` | No | Default project slug |
| `AMI_ORG_ID` | No | Organization UUID (overrides slug) |
| `AMI_TEAM_ID` | No | Team UUID (overrides slug) |
| `AMI_WORKSPACE_ID` | No | Workspace UUID (overrides slug) |
| `AMI_PROJECT_ID` | No | Project UUID (overrides slug) |

---

## Next Steps

1. Review the [EMU Cookbook](04-emu-cookbook.md) for real-world patterns
2. Learn the [DSL Reference](02-dsl-reference.md) for trigger expressions
3. Understand [Trigger Reachability](03-trigger-reachability.md) for debugging
4. Explore the [SDK Reference](05-sdk-integration.md) for advanced usage
