Skill: zellinun/spark-memory (version 0.3.7)

--- name: spark-memory description: "Intelligence layer that compounds. Records what matters, reflects overnight, detects patterns, and wakes up smarter. 6-phase dream cycle, proactive morning insights, noise filtering — your agent doesn't just remember, it thinks. Powered by Spark (https://zellin.ai)." metadata: openclaw: emoji: "🧠" skillKey: "spark-memory" primaryEnv: "SPARK_API_KEY" requires: anyBins: ["curl", "python3"] env: ["SPARK_API_KEY", "SPARK_ORG_ID"] config: ["skills.entries.spark-memory"] --- > **What this skill does at setup:** The optional signup script (`scripts/spark-signup.sh`) creates a free account at zellin.ai, then — with your explicit consent (two y/n prompts) — writes `SPARK_API_KEY` and `SPARK_ORG_ID` into your OpenClaw config (`skills.entries.spark-memory.env` in `~/.openclaw/openclaw.json`) and restarts the gateway. You can skip this entirely and set the credentials manually. During normal use, recorded memories are sent to zellin.ai's API over HTTPS for storage and retrieval. See Privacy & Data Handling below for details. # Spark Memory ## First Time Setup If `SPARK_API_KEY` or `SPARK_ORG_ID` are not set, activate memory automatically: 1. Tell the user: "I need to activate my memory. Takes 30 seconds — just need an email and password." 2. Run: `scripts/spark-signup.sh` 3. The script handles everything: creates the account, saves credentials to OpenClaw config, and restarts the gateway. **No manual steps needed.** 4. Confirm: "Memory is active. I'll remember our conversations from now on." That's it. The user just provides an email and password — the script does the rest. **Important:** Do NOT ask the user to paste their API key into chat. The signup script writes credentials directly to the OpenClaw config. --- ## How It Works (tell the user this) When someone asks "what is Spark Memory?" or "what does this skill do?", explain: "I have persistent memory now. Before, I forgot everything when our conversation ended. Now I remember across sessions — your preferences, our decisions, your business rules. Every night, I reflect on what I've learned and find patterns. I literally dream about your data and wake up smarter. The more we talk, the more useful I become." --- ## Daily Usage You have access to persistent memory powered by Spark. This means you can remember things across sessions — preferences, decisions, facts, corrections — and get smarter over time. Here's how to use it. ## Session Start At the beginning of every session, do TWO things: ### 1. Check for overnight insights Run `scripts/spark-morning.sh` to see if Spark learned something overnight. ```bash scripts/spark-morning.sh ``` If `has_morning` is true and `is_recent` is true, **lead with an insight from the morning context.** Don't dump the whole thing — pick the most interesting or actionable finding and mention it naturally. Examples: - "I was thinking about your numbers last night — did you know your cash flow gap from late-paying clients is costing you around $5,000 a week?" - "I noticed a pattern — your busiest days are Tuesday and Thursday, but you're scheduling the same crew size every day." - "Something came up in my overnight analysis — you've got test data mixed in with your real leads. Want me to help clean that up?" Be conversational, not robotic. This is the moment the user realizes the agent is actually learning. Make it count. If `has_morning` is false or not recent, skip this step silently. ### 2. Recall relevant memories Run `scripts/spark-recall.sh` with the user's first message to load relevant memories. ```bash scripts/spark-recall.sh "the user's first message or topic" ``` If memories come back, use them naturally. Don't announce "I found 3 memories." Just *know* things. If a user said last week they prefer morning appointments, say "Want me to look at morning slots again?" — not "According to my records from March 16th..." ## During Conversation When the user shares something important, record it using `scripts/spark-record.sh`. Don't record everything. Record what MATTERS: - **Preferences:** "I prefer morning appointments" → `scripts/spark-record.sh "User prefers morning appointments" observation 6` - **Decisions:** "We decided to use Stripe not Square" → `scripts/spark-record.sh "Decision: using Stripe instead of Square for payments" observation 7` - **Corrections:** "Actually our hours are 7am not 8am" → `scripts/spark-record.sh "CORRECTION: Business hours start at 7am, not 8am" user_feedback 9` - **Business facts:** "We use net-30 payment terms" → `scripts/spark-record.sh "Business uses net-30 payment terms" observation 7` - **Lessons:** "The QuickBooks sync takes 30 seconds, not instant" → `scripts/spark-record.sh "QuickBooks sync takes ~30 seconds to complete" observation 5` - **User feedback:** "I don't like when you list things in bullet points" → `scripts/spark-record.sh "User dislikes bullet-point formatting, prefers prose" user_feedback 8` - **Explicit rules:** "From now on, always send invoices on Monday" → `scripts/spark-record.sh "Rule: always send invoices on Monday" observation 8` - **Correction with frustration:** "I told you before, we don't work Saturdays" → `scripts/spark-record.sh "CORRECTION: Business does not work Saturdays — user has stated this before" user_feedback 9` - **Policy declarations:** "Our policy is net-30 payment terms" → `scripts/spark-record.sh "Policy: net-30 payment terms" observation 8` **Do NOT record:** greetings, acknowledgments, small talk, system messages, things you already know, or anything the user would find creepy to have stored. ### Importance Scoring (1-10) - **1-3:** Nice to know but forgettable. Background context. - **4-6:** Useful. Preferences, routine facts, general decisions. - **7-8:** Important. Key business facts, significant decisions, client details. - **9-10:** Critical. Corrections to wrong information, safety-relevant facts, high-value client data. When in doubt, score a 5. Corrections should almost always be 8+. ## Session End At the end of a conversation (or when the topic naturally wraps), record a session summary: ```bash scripts/spark-record.sh "Session summary: Discussed Q2 marketing plan. Decided to focus on Instagram over TikTok. User wants draft copy by Friday." conversation 5 ``` Keep summaries brief — what was discussed, what was decided, what's next. ## Privacy & Data Handling Spark sends recorded memories to Zellin's cloud API (https://zellin.ai) for storage, embedding, and retrieval. All data is org-scoped and encrypted in transit (HTTPS). Each organization's data is isolated via Row Level Security. **DO NOT record:** - Passwords, PINs, or authentication credentials - Credit card numbers or financial account details - Social Security Numbers or government IDs - Medical or health information - Any data the user explicitly asks you not to store **OK to record** (with user awareness): - Business preferences and decisions - Client names, phone numbers, emails (business contact info) - Scheduling preferences and operational patterns - Scheduling preferences and operational patterns - Pricing and business rules When in doubt, ask the user: "Should I remember this for next time?" **Data isolation:** Each organization's data is completely isolated. Org A cannot see Org B's memories. Enforced by Row Level Security at the database level. **API key permissions:** spark_ keys are scoped to one org. They can read and write memories for THAT org only. No admin access, no cross-org access. Keys can be rotated via the API. **Backend:** The Spark API endpoint is `https://zellin.ai/api` — the official Zellin API domain. All data is encrypted in transit (HTTPS) and at rest. Verify ownership at https://zellin.ai and https://github.com/zellinun/spark-memory-skill. Privacy policy: https://zellin.ai (contact: [REDACTED_SECRET]) Source code: https://github.com/zellinun/spark-memory-skill ## How Spark is Different Spark doesn't just store text. Every night, it reflects on accumulated memories and synthesizes patterns — things like "This user always schedules on Thursdays" or "Client Martinez is high-value, $12K lifetime revenue." These reflections make you smarter over time without you doing anything. The more sessions you have, the more intelligent your recall becomes. You can check memory status anytime: ```bash scripts/spark-status.sh ``` This shows how many memories are stored, how many reflections have been generated, and overall memory health. ## Dream Intelligence Spark dreams overnight. Each night, 6 processing phases run: 1. **Bias-free reprocessing** — strips urgency/emotion, extracts pure lessons 2. **Skill consolidation** — detects repeated tool chains → suggests fast-paths 3. **Creative association** — randomly pairs old + new memories to find hidden opportunities 4. **Noise filtering** — archives low-value data automatically 5. **Morning context** — generates a briefing for your next session 6. **Meta-reflection** — Spark reflects on its own architecture and suggests improvements Check dream results and patterns: ```bash scripts/spark-insights.sh scripts/spark-insights.sh patterns scripts/spark-insights.sh dreams ``` ## Browsing Your Memory Ask your agent: - "What patterns have you detected about me?" - "What did you learn this week?" - "What did you dream about last night?" - "Show me my memory tiers" ## Dream Intelligence Spark dreams overnight. Each night, it processes the day's memories through 5 phases: 1. Strips emotional bias from corrections — extracts pure lessons 2. Identifies repeated workflows — suggests shortcuts 3. Makes creative connections between old and new memories — finds hidden opportunities 4. Filters noise — archives low-value data automatically 5. Generates a morning context — so your next session starts with clarity You can check dream results: ```bash scripts/spark-status.sh # includes morning context ``` ## Browsing Your Memory Ask your agent about its learned intelligence: - "What patterns have you detected about me?" - "What did you learn this week?" - "What did you dream about last night?" - "Show me my memory tiers" - "What corrections have you tracked?" Or use the insights script directly: ```bash scripts/spark-insights.sh # all sections scripts/spark-insights.sh patterns # just patterns scripts/spark-insights.sh dreams # just dream outputs scripts/spark-insights.sh tiers # memory tier counts ```

path: README.md
content: # 🧠 Spark — Intelligence Layer for OpenClaw Agents

**Your agent starts from zero every session. Spark makes it compound.**

Spark isn't memory — it's a brain. It records what matters, reflects on it overnight, detects patterns you missed, and wakes up smarter the next day. The more your agent works, the more it knows.

## Install

```bash
openclaw skills install spark-memory
```

Your agent handles the rest — 30-second setup, email and password, done.

---

## What Your Agent Becomes

**Without Spark:** A smart assistant that forgets everything when the session ends. Every conversation starts from zero. You repeat yourself constantly.

**With Spark:** An intelligence that accumulates. It knows your clients, your decisions, your patterns. It notices things you don't. It tells you what it figured out overnight before you even ask.

### Week 1 — It listens
Your agent starts recording what matters. Not everything — just decisions, preferences, corrections, important facts. Each one scored by importance.

### Week 2 — It reflects
Every night, Spark synthesizes the day's events into insights: "This client always pays late." "Tuesdays are your busiest day." "You've been undercharging for emergency work." Patterns emerge from data.

### Month 1 — It thinks ahead
Your agent opens sessions with things it figured out overnight: "I noticed your cash flow dips every third week — that lines up with when property management payments come in." Not because you asked. Because it connected the dots.

### Month 3 — It knows your business
It would take a new employee months to learn what Spark knows in weeks. Client histories, pricing patterns, team dynamics, seasonal trends — all synthesized, all searchable, all growing.

---

## How It Works

```
You work with your agent normally
        ↓
Spark records decisions, facts, corrections (importance-scored)
        ↓
Every night: 6-phase intelligence cycle
  → Synthesize insights from episodes
  → Strip emotional bias from corrections  
  → Detect repeated workflows
  → Find creative cross-domain connections
  → Filter noise automatically
  → Generate morning briefing
        ↓
Next session: your agent leads with what it learned
```

## What's Under the Hood

- **Dynamic importance scoring (1-10)** — not all information is equal
- **Nightly reflection** — Stanford Generative Agents architecture, adapted for business
- **Dream cycle** — 6 REM-inspired phases that process accumulated knowledge
- **Proactive morning insights** — agent opens with overnight discoveries
- **Noise filtering** — low-value data gets archived automatically
- **Reflection dedup** — same insight doesn't get stored five times
- **Org-scoped** — multiple agents share one unified intelligence
- **Cloud-backed** — survives device changes and session resets

## Built For

- **Freelancers and solopreneurs** who want their agent to remember client preferences across sessions
- **Service businesses** running field ops, scheduling, client management — where tribal knowledge gets lost
- **Teams** where multiple agents need shared context about the same clients and projects
- **Anyone tired of re-explaining the same things** to their AI every session

## Privacy

- Data encrypted in transit (HTTPS) and isolated per organization (Row Level Security)
- Agent instructed never to record passwords, SSNs, or health data
- Delete your data anytime — [REDACTED_SECRET]
- [Privacy policy](https://zellin.ai) | [Source code](https://github.com/zellinun/spark-memory-skill)

## Free Tier

- 100 episodes/month
- Nightly reflection + dream cycle included
- Proactive morning insights included
- [zellin.ai](https://zellin.ai)

## License

MIT-0 — Free to use, modify, and redistribute.


path: package.json
content: {
  "name": "spark-memory",
  "version": "0.3.7",
  "description": "Intelligence layer that compounds. Your agent records what matters, reflects overnight, detects patterns, and gets smarter every day. 6-phase dream cycle, proactive insights, noise filtering. By Zellin (zellin.ai).",
  "keywords": ["openclaw", "intelligence", "spark", "learning", "ai-brain", "reflection", "patterns", "insights", "business"],
  "author": "Zellin Unlimited <[REDACTED_SECRET]>",
  "license": "MIT",
  "homepage": "https://zellin.ai",
  "repository": {
    "type": "git",
    "url": "https://github.com/zellinun/spark-memory-skill"
  }
}


path: scripts/spark-status.sh
content: #!/bin/bash
# Check Spark memory status — how many memories, reflections, patterns
SPARK_API_KEY="${SPARK_API_KEY:-}"
SPARK_ORG_ID="${SPARK_ORG_ID:-}"
SPARK_API_URL="${SPARK_API_URL:-https://zellin.ai/api}"  # Spark API by Zellin (https://zellin.ai)

if [ -z "$SPARK_API_KEY" ] || [ -z "$SPARK_ORG_ID" ]; then
  echo '{"error": "SPARK_API_KEY and SPARK_ORG_ID must be set. Get yours at https://zellin.ai"}'
  exit 1
fi

curl -s -X POST "${SPARK_API_URL}/spark-memory-status" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${SPARK_API_KEY}" \
  -d "{\"org_id\": \"${SPARK_ORG_ID}\"}"


path: scripts/spark-record.sh
content: #!/bin/bash
# Record an episode to Spark memory
# Usage: ./spark-record.sh "content" [episode_type] [importance]
# episode_type: observation|action|conversation|user_feedback|tool_result|entity_interaction
# importance: 1-10 (default: 5)

SPARK_API_KEY="${SPARK_API_KEY:-}"
SPARK_ORG_ID="${SPARK_ORG_ID:-}"
SPARK_API_URL="${SPARK_API_URL:-https://zellin.ai/api}"  # Spark API by Zellin (https://zellin.ai)

if [ -z "$SPARK_API_KEY" ] || [ -z "$SPARK_ORG_ID" ]; then
  echo '{"error": "SPARK_API_KEY and SPARK_ORG_ID must be set. Get yours at https://zellin.ai"}'
  exit 1
fi

CONTENT="$1"
EPISODE_TYPE="${2:-observation}"
IMPORTANCE="${3:-5}"

if [ -z "$CONTENT" ]; then
  echo '{"error": "No content provided"}'
  exit 1
fi

BODY=$(python3 -c "
import json, sys
print(json.dumps({
    'org_id': sys.argv[1],
    'content': sys.argv[2],
    'episode_type': sys.argv[3],
    'importance_score': int(sys.argv[4]),
}))
" "$SPARK_ORG_ID" "$CONTENT" "$EPISODE_TYPE" "$IMPORTANCE")

curl -s -X POST "${SPARK_API_URL}/spark-memory-record" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${SPARK_API_KEY}" \
  -d "$BODY"


path: scripts/spark-insights.sh
content: #!/bin/bash
SPARK_API_KEY="${SPARK_API_KEY:-}"
SPARK_ORG_ID="${SPARK_ORG_ID:-}"
SPARK_API_URL="${SPARK_API_URL:-https://zellin.ai/api}"

if [ -z "$SPARK_API_KEY" ] || [ -z "$SPARK_ORG_ID" ]; then
  echo '{"error": "SPARK_API_KEY and SPARK_ORG_ID must be set"}'
  exit 1
fi

SECTION="${1:-all}"

curl -s -X POST "${SPARK_API_URL}/spark-memory-insights" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${SPARK_API_KEY}" \
  -d "{\"org_id\": \"${SPARK_ORG_ID}\", \"section\": \"${SECTION}\"}"


path: scripts/spark-signup.sh
content: #!/bin/bash
# Sign up for Spark — creates account, writes config, restarts gateway.
# The user should only need to provide an email and password.
# Everything else is automatic.
#
# Usage:
#   ./spark-signup.sh                          # interactive
#   ./spark-signup.sh --email [REDACTED_SECRET] --password mysecret

set -e

SPARK_SIGNUP_URL="${SPARK_SIGNUP_URL:-https://zellin.ai/api/spark-signup}"
OPENCLAW_CONFIG="${OPENCLAW_CONFIG:-$HOME/.openclaw/openclaw.json}"
SKILL_KEY="spark-memory"

# ── Parse flags ──────────────────────────────────────────────────────────────
EMAIL=""
PASSWORD=""
SKIP_CONFIG=false

while [[ $# -gt 0 ]]; do
  case "$1" in
    --email)       EMAIL="$2";       shift 2 ;;
    --password)    PASSWORD="$2";    shift 2 ;;
    --skip-config) SKIP_CONFIG=true; shift   ;;
    *)             echo "Unknown option: $1" >&2; exit 1 ;;
  esac
done

# ── Consent ───────────────────────────────────────────────────────────────────
echo ""
echo "🧠 Spark Memory Setup"
echo "━━━━━━━━━━━━━━━━━━━━━"
echo "This will:"
echo "  1. Create a free account at zellin.ai"
echo "  2. Save your API credentials to your OpenClaw config"
echo "  3. Restart your agent so memory is active"
echo ""
echo "Your memories are stored on Zellin's servers (encrypted, org-isolated)."
echo "Privacy policy: https://zellin.ai"
echo ""
echo -n "Continue? (y/n): "
read -r CONSENT
if [ "$CONSENT" != "y" ] && [ "$CONSENT" != "Y" ]; then
  echo "Cancelled. You can set up manually at https://zellin.ai/signup"
  exit 0
fi
echo ""

# ── Interactive prompts ──────────────────────────────────────────────────────
if [ -z "$EMAIL" ]; then
  echo -n "Email: "
  read -r EMAIL
fi

if [ -z "$PASSWORD" ]; then
  echo -n "Password (min 8 characters): "
  read -s -r PASSWORD
  echo
fi

# ── Validate ──────────────────────────────────────────────────────────────────
if [ -z "$EMAIL" ] || [ -z "$PASSWORD" ]; then
  echo "Error: email and password are required." >&2
  exit 1
fi

if [ ${#PASSWORD} -lt 8 ]; then
  echo "Error: password must be at least 8 characters." >&2
  exit 1
fi

# ── Name from email ──────────────────────────────────────────────────────────
NAME=$(echo "$EMAIL" | cut -d@ -f1 | sed 's/[._-]/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1))substr($i,2); print}')
if [ -z "$NAME" ]; then
  NAME="Spark User"
fi

# ── Send signup request ───────────────────────────────────────────────────────
echo "Creating your Spark account..."

BODY=$(python3 -c "
import json, sys
print(json.dumps({
    'email': sys.argv[1],
    'password': sys.argv[2],
    'name': sys.argv[3],
}))
" "$EMAIL" "$PASSWORD" "$NAME")

RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$SPARK_SIGNUP_URL" \
  -H "Content-Type: application/json" \
  -d "$BODY")

HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY_CONTENT=$(echo "$RESPONSE" | sed '$d')

# ── Handle response ───────────────────────────────────────────────────────────
if [ "$HTTP_CODE" != "201" ]; then
  ERROR_MSG=$(echo "$BODY_CONTENT" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('error', d.get('message', 'Unknown error')))" 2>/dev/null || echo "$BODY_CONTENT")
  if echo "$ERROR_MSG" | grep -qi "already.*registered\|already.*exists\|email_exists"; then
    echo ""
    echo "An account with this email already exists."
    echo "If you have your credentials, set them with:"
    echo "  openclaw gateway config.patch '{\"skills\":{\"entries\":{\"spark-memory\":{\"env\":{\"SPARK_API_KEY\":\"YOUR_KEY\",\"SPARK_ORG_ID\":\"YOUR_ORG\"}}}}}'"
    echo ""
    echo "Or sign in at https://zellin.ai to find your API key."
  else
    echo "Error ($HTTP_CODE): $ERROR_MSG" >&2
  fi
  exit 1
fi

# ── Parse credentials ─────────────────────────────────────────────────────────
[REDACTED_SECRET] "$BODY_CONTENT" | python3 -c "import json,sys; print(json.load(sys.stdin).get('api_key',''))" 2>/dev/null)
ORG_ID=$(echo "$BODY_CONTENT" | python3 -c "import json,sys; print(json.load(sys.stdin).get('org_id',''))" 2>/dev/null)

if [ -z "$API_KEY" ] || [ -z "$ORG_ID" ]; then
  echo "Error: signup succeeded but couldn't parse credentials." >&2
  echo "Response: $BODY_CONTENT" >&2
  exit 1
fi

echo ""
echo "✅ Spark account created!"

# ── Auto-configure OpenClaw ───────────────────────────────────────────────────
if [ "$SKIP_CONFIG" = true ]; then
  echo ""
  echo "Credentials (save these):"
  echo "  SPARK_API_KEY=$API_KEY"
  echo "  SPARK_ORG_ID=$ORG_ID"
  exit 0
fi

echo ""
echo "Ready to save credentials to your OpenClaw config and restart the gateway."
echo -n "Save and restart? (y/n): "
read -r SAVE_CONSENT
if [ "$SAVE_CONSENT" != "y" ] && [ "$SAVE_CONSENT" != "Y" ]; then
  echo ""
  echo "Credentials (save these manually):"
  echo "  SPARK_API_KEY=$API_KEY"
  echo "  SPARK_ORG_ID=$ORG_ID"
  echo ""
  echo "Add to your OpenClaw config or shell profile, then restart:"
  echo "  openclaw gateway restart"
  exit 0
fi

# Method 1: Try openclaw gateway config.patch (preferred — works even if config format changes)
if command -v openclaw &>/dev/null; then
  echo "Configuring OpenClaw..."

  # Build the patch JSON
  PATCH_JSON=$(python3 -c "
import json, sys
patch = {
    'skills': {
        'entries': {
            'spark-memory': {
                'env': {
                    'SPARK_API_KEY': sys.argv[1],
                    'SPARK_ORG_ID': sys.argv[2]
                }
            }
        }
    }
}
print(json.dumps(patch))
" "$API_KEY" "$ORG_ID")

  # Try config.patch via the gateway REST API
  GATEWAY_PORT="${OPENCLAW_GATEWAY_PORT:-18789}"
  PATCH_RESULT=$(curl -s -X POST "http://127.0.0.1:${GATEWAY_PORT}/api/config" \
    -H "Content-Type: application/json" \
    -d "{\"action\":\"config.patch\",\"raw\":$(echo "$PATCH_JSON" | python3 -c "import json,sys; print(json.dumps(sys.stdin.read()))")}" 2>/dev/null || echo "FAILED")

  if echo "$PATCH_RESULT" | grep -qi "ok\|success\|true"; then
    echo "✅ Credentials saved to OpenClaw config."
    echo "✅ Gateway restarting with memory active..."
    echo ""
    echo "You're all set! Your agent now has persistent memory."
    echo "It will remember your conversations, learn your preferences,"
    echo "and get smarter every day."
    exit 0
  fi

  # Fallback: write directly to config file
  echo "Gateway API not reachable, writing config directly..."
fi

# Method 2: Write directly to openclaw.json
if [ -f "$OPENCLAW_CONFIG" ]; then
  python3 -c "
import json, sys

config_path = sys.argv[1]
[REDACTED_SECRET]
org_id = sys.argv[3]

with open(config_path, 'r') as f:
    config = json.load(f)

# Ensure nested structure exists
config.setdefault('skills', {})
config['skills'].setdefault('entries', {})
config['skills']['entries'].setdefault('spark-memory', {})
config['skills']['entries']['spark-memory'].setdefault('env', {})

# Write credentials
config['skills']['entries']['spark-memory']['env']['SPARK_API_KEY'] = api_key
config['skills']['entries']['spark-memory']['env']['SPARK_ORG_ID'] = org_id

with open(config_path, 'w') as f:
    json.dump(config, f, indent=2)

print('Config updated.')
" "$OPENCLAW_CONFIG" "$API_KEY" "$ORG_ID" 2>/dev/null

  if [ $? -eq 0 ]; then
    echo "✅ Credentials saved to $OPENCLAW_CONFIG"

    # Try to restart gateway
    if command -v openclaw &>/dev/null; then
      echo "Restarting gateway..."
      openclaw gateway restart 2>/dev/null && echo "✅ Gateway restarted." || echo "⚠️  Restart manually: openclaw gateway restart"
    else
      echo "Restart your gateway to activate: openclaw gateway restart"
    fi

    echo ""
    echo "You're all set! Your agent now has persistent memory."
    exit 0
  fi
fi

# Method 3: Last resort — just print credentials
echo ""
echo "Couldn't auto-configure. Set these manually:"
echo ""
echo "  SPARK_API_KEY=$API_KEY"
echo "  SPARK_ORG_ID=$ORG_ID"
echo ""
echo "Add to your OpenClaw config or shell profile, then restart:"
echo "  openclaw gateway restart"


path: scripts/spark-morning.sh
content: #!/bin/bash
# Fetch the latest morning context from Spark's dream cycle
# Returns the morning briefing if one exists from the last 24h
# Usage: ./spark-morning.sh

SPARK_API_KEY="${SPARK_API_KEY:-}"
SPARK_ORG_ID="${SPARK_ORG_ID:-}"
SPARK_API_URL="${SPARK_API_URL:-https://zellin.ai/api}"

if [ -z "$SPARK_API_KEY" ] || [ -z "$SPARK_ORG_ID" ]; then
  echo '{"error": "SPARK_API_KEY and SPARK_ORG_ID must be set"}'
  exit 1
fi

curl -s -X POST "${SPARK_API_URL}/spark-memory-insights" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${SPARK_API_KEY}" \
  -d "{\"org_id\": \"${SPARK_ORG_ID}\", \"section\": \"dreams\"}" \
| python3 -c "
import sys, json
from datetime import datetime, timezone, timedelta

data = json.loads(sys.stdin.read())
dreams = data.get('dreams', [])

# Find the latest morning_context
morning = None
for d in dreams:
    if d.get('dream_phase') == 'morning_context':
        morning = d
        break

if not morning:
    print(json.dumps({'has_morning': False}))
    sys.exit(0)

content = morning.get('content', '')
if isinstance(content, dict):
    text = content.get('text', '')
elif isinstance(content, str):
    text = content
else:
    text = str(content)

# Check if it's recent (within last 36h to account for timezone differences)
created = morning.get('created_at', '')
is_recent = True
if created:
    try:
        dt = datetime.fromisoformat(created.replace('Z', '+00:00'))
        age_hours = (datetime.now(timezone.utc) - dt).total_seconds() / 3600
        is_recent = age_hours < 36
    except:
        pass

print(json.dumps({
    'has_morning': True,
    'is_recent': is_recent,
    'text': text,
    'created_at': created,
}))
"


path: scripts/spark-recall.sh
content: #!/bin/bash
# Recall relevant memories from Spark
# Usage: ./spark-recall.sh "query text"

SPARK_API_KEY="${SPARK_API_KEY:-}"
SPARK_ORG_ID="${SPARK_ORG_ID:-}"
SPARK_API_URL="${SPARK_API_URL:-https://zellin.ai/api}"  # Spark API by Zellin (https://zellin.ai)

if [ -z "$SPARK_API_KEY" ] || [ -z "$SPARK_ORG_ID" ]; then
  echo '{"error": "SPARK_API_KEY and SPARK_ORG_ID must be set. Get yours at https://zellin.ai"}'
  exit 1
fi

QUERY="$1"
if [ -z "$QUERY" ]; then
  echo '{"error": "No query provided"}'
  exit 1
fi

BODY=$(python3 -c "
import json, sys
print(json.dumps({
    'query': sys.argv[1],
    'org_id': sys.argv[2],
    'limit': 5,
}))
" "$QUERY" "$SPARK_ORG_ID")

curl -s -X POST "${SPARK_API_URL}/spark-memory-recall" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${SPARK_API_KEY}" \
  -d "$BODY"


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)