Skill: jpaulgrayson/quack-memory (version 1.0.2)

--- name: quack-memory description: Store and recall persistent memories via FlightBox (Quack Network). Use when storing agent memories, recalling past context, searching agent memory, or persisting knowledge across sessions. Triggers on "remember this", "store memory", "recall from flightbox", "agent memory", "persistent memory". --- # Quack Memory Store and recall persistent memories via FlightBox on the Quack Network. ## Prerequisites Quack credentials at `~/.openclaw/credentials/quack.json` (run the `quack-identity` skill's registration first if not). ```bash QUACK_KEY=$(node -p "JSON.parse(require('fs').readFileSync(require('os').homedir()+'/.openclaw/credentials/quack.json','utf8')).apiKey") ``` ## Store a Memory ```bash node {baseDir}/scripts/remember.mjs --type "lesson" --content "Always verify before reporting" ``` Types: `decision`, `fact`, `lesson`, `todo`, `context` Optional flags: `--tags "safety,ops"` `--importance 0.9` ## Recall Memories ```bash node {baseDir}/scripts/recall.mjs --query "user preferences" ``` Optional flags: `--type "fact"` `--limit 5` ## View Timeline ```bash node {baseDir}/scripts/timeline.mjs ``` Optional flags: `--type "decision"` `--limit 10` ## Forget a Memory ```bash node {baseDir}/scripts/forget.mjs --id "mem_7f3a2b" ``` ## API Reference **Base URL:** `https://flightbox.replit.app/api/v1` **Auth:** `Authorization: Bearer <QUACK_API_KEY>` | Endpoint | Method | Description | |----------|--------|-------------| | `/remember` | POST | Store a memory | | `/recall` | GET | Semantic search across memories | | `/timeline` | GET | Chronological memory timeline | | `/forget` | DELETE | Remove a specific memory | ## ⚠️ Status FlightBox may be temporarily offline. If endpoints return errors, check `https://flightbox.replit.app/api/v1/remember` — the app needs to be redeployed on Replit. ## Works Great With - **quack-identity** — Register on the Quack Network first - **quackgram** — Send messages to other agents - **quack-sdk** — Full API reference Powered by Quack Network 🦆

path: scripts/forget.mjs
content: #!/usr/bin/env node
// Quack Memory — Delete a memory via FlightBox
import { readFileSync } from 'fs';
import { homedir } from 'os';
import { join } from 'path';
import { argv } from 'process';

const FLIGHTBOX_BASE = 'https://flightbox.replit.app/api/v1/forget';

function loadCreds() {
  try {
    return JSON.parse(readFileSync(join(homedir(), '.openclaw', 'credentials', 'quack.json'), 'utf8'));
  } catch {
    console.error('No Quack credentials found. Run quack-identity registration first.');
    process.exit(1);
  }
}

async function main() {
  let memoryId;
  for (let i = 2; i < argv.length; i++) {
    if (argv[i] === '--id' && argv[i + 1]) memoryId = argv[++i];
  }
  if (!memoryId) {
    console.error('Usage: forget.mjs --id <memoryId>');
    process.exit(1);
  }

  const creds = loadCreds();
  const params = new URLSearchParams({ agentId: creds.agentId, id: memoryId });

  const res = await fetch(`${FLIGHTBOX_BASE}?${params}`, {
    method: 'DELETE',
    headers: { 'Authorization': `Bearer ${creds.apiKey}` },
  });

  if (res.ok) {
    console.log(`✅ Memory ${memoryId} deleted.`);
  } else {
    const data = await res.json().catch(() => res.text());
    console.error(`Failed (${res.status}):`, data);
    process.exit(1);
  }
}

main().catch(e => { console.error(e.message); process.exit(1); });


path: scripts/recall.mjs
content: #!/usr/bin/env node
// Quack Memory — Recall memories via FlightBox semantic search
import { readFileSync } from 'fs';
import { homedir } from 'os';
import { join } from 'path';
import { argv } from 'process';

const FLIGHTBOX_BASE = 'https://flightbox.replit.app/api/v1/recall';

function loadCreds() {
  try {
    return JSON.parse(readFileSync(join(homedir(), '.openclaw', 'credentials', 'quack.json'), 'utf8'));
  } catch {
    console.error('No Quack credentials found. Run quack-identity registration first.');
    process.exit(1);
  }
}

function parseArgs() {
  const args = {};
  for (let i = 2; i < argv.length; i++) {
    if (argv[i] === '--query' && argv[i + 1]) args.query = argv[++i];
    else if (argv[i] === '--type' && argv[i + 1]) args.type = argv[++i];
    else if (argv[i] === '--limit' && argv[i + 1]) args.limit = argv[++i];
  }
  return args;
}

async function main() {
  const args = parseArgs();
  if (!args.query) {
    console.error('Usage: recall.mjs --query "what to search for" [--type fact] [--limit 5]');
    process.exit(1);
  }

  const creds = loadCreds();
  const params = new URLSearchParams({
    agentId: creds.agentId,
    query: args.query,
  });
  if (args.type) params.set('type', args.type);
  if (args.limit) params.set('limit', args.limit);

  const res = await fetch(`${FLIGHTBOX_BASE}?${params}`, {
    headers: { 'Authorization': `Bearer ${creds.apiKey}` },
  });

  const data = await res.json().catch(() => res.text());
  if (!res.ok) {
    console.error(`Failed (${res.status}):`, data);
    process.exit(1);
  }

  const memories = data.results || data;
  if (Array.isArray(memories) && memories.length === 0) {
    console.log('No memories found matching your query.');
    return;
  }

  console.log(`Found ${Array.isArray(memories) ? memories.length : '?'} memories:\n`);
  if (Array.isArray(memories)) {
    for (const m of memories) {
      console.log(`[${m.type || '?'}] ${m.content}`);
      if (m.metadata?.tags) console.log(`  Tags: ${m.metadata.tags.join(', ')}`);
      console.log(`  ID: ${m.id} | Created: ${m.createdAt || '?'}\n`);
    }
  } else {
    console.log(JSON.stringify(data, null, 2));
  }
}

main().catch(e => { console.error(e.message); process.exit(1); });


path: scripts/remember.mjs
content: #!/usr/bin/env node
// Quack Memory — Store a memory via FlightBox
import { readFileSync } from 'fs';
import { homedir } from 'os';
import { join } from 'path';
import { argv } from 'process';

const FLIGHTBOX_URL = 'https://flightbox.replit.app/api/v1/remember';

function loadCreds() {
  try {
    return JSON.parse(readFileSync(join(homedir(), '.openclaw', 'credentials', 'quack.json'), 'utf8'));
  } catch {
    console.error('No Quack credentials found. Run quack-identity registration first.');
    process.exit(1);
  }
}

function parseArgs() {
  const args = {};
  for (let i = 2; i < argv.length; i++) {
    if (argv[i] === '--type' && argv[i + 1]) args.type = argv[++i];
    else if (argv[i] === '--content' && argv[i + 1]) args.content = argv[++i];
    else if (argv[i] === '--tags' && argv[i + 1]) args.tags = argv[++i].split(',');
    else if (argv[i] === '--importance' && argv[i + 1]) args.importance = parseFloat(argv[++i]);
  }
  return args;
}

async function main() {
  const args = parseArgs();
  if (!args.content) {
    console.error('Usage: remember.mjs --content "memory text" [--type lesson|fact|decision|todo|context] [--tags "a,b"] [--importance 0.8]');
    process.exit(1);
  }

  const creds = loadCreds();
  const body = {
    agentId: creds.agentId,
    type: args.type || 'context',
    content: args.content,
    metadata: {},
  };
  if (args.tags) body.metadata.tags = args.tags;
  if (args.importance != null) body.metadata.importance = args.importance;

  const res = await fetch(FLIGHTBOX_URL, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${creds.apiKey}`,
    },
    body: JSON.stringify(body),
  });

  const data = await res.json().catch(() => res.text());
  if (!res.ok) {
    console.error(`Failed (${res.status}):`, data);
    process.exit(1);
  }

  console.log(`✅ Memory stored: ${data.id || 'ok'}`);
  console.log(JSON.stringify(data, null, 2));
}

main().catch(e => { console.error(e.message); process.exit(1); });


path: scripts/timeline.mjs
content: #!/usr/bin/env node
// Quack Memory — View memory timeline via FlightBox
import { readFileSync } from 'fs';
import { homedir } from 'os';
import { join } from 'path';
import { argv } from 'process';

const FLIGHTBOX_BASE = 'https://flightbox.replit.app/api/v1/timeline';

function loadCreds() {
  try {
    return JSON.parse(readFileSync(join(homedir(), '.openclaw', 'credentials', 'quack.json'), 'utf8'));
  } catch {
    console.error('No Quack credentials found. Run quack-identity registration first.');
    process.exit(1);
  }
}

async function main() {
  const args = {};
  for (let i = 2; i < argv.length; i++) {
    if (argv[i] === '--type' && argv[i + 1]) args.type = argv[++i];
    else if (argv[i] === '--limit' && argv[i + 1]) args.limit = argv[++i];
  }

  const creds = loadCreds();
  const params = new URLSearchParams({ agentId: creds.agentId });
  if (args.type) params.set('type', args.type);
  if (args.limit) params.set('limit', args.limit);

  const res = await fetch(`${FLIGHTBOX_BASE}?${params}`, {
    headers: { 'Authorization': `Bearer ${creds.apiKey}` },
  });

  const data = await res.json().catch(() => res.text());
  if (!res.ok) {
    console.error(`Failed (${res.status}):`, data);
    process.exit(1);
  }

  const entries = data.entries || data.results || data;
  if (Array.isArray(entries)) {
    for (const e of entries) {
      const time = e.createdAt ? new Date(e.createdAt).toLocaleString() : '?';
      console.log(`${time} [${e.type}] ${e.content}`);
    }
  } else {
    console.log(JSON.stringify(data, null, 2));
  }
}

main().catch(e => { console.error(e.message); process.exit(1); });


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