# Setup Memory

> |

- **Type:** Skill
- **Install:** `agentstack add skill-timurgaleev-vibestack-setup-memory`
- **Verified:** Pending review
- **Seller:** [timurgaleev](https://agentstack.voostack.com/s/timurgaleev)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [timurgaleev](https://github.com/timurgaleev)
- **Source:** https://github.com/timurgaleev/vibestack/tree/main/skills/setup-memory

## Install

```sh
agentstack add skill-timurgaleev-vibestack-setup-memory
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

## When to invoke

Use when: "setup memory", "setup secondbrain", "connect secondbrain", "start secondbrain", "install secondbrain", "configure memory for this machine".

## Preamble

```bash
eval "$(~/.vibestack/bin/vibe-slug 2>/dev/null)" 2>/dev/null || SLUG="unknown"
_LEARN_FILE="${VIBESTACK_HOME:-$HOME/.vibestack}/projects/${SLUG:-unknown}/learnings.jsonl"
if [ -f "$_LEARN_FILE" ]; then
  _LEARN_COUNT=$(wc -l /dev/null | tr -d ' ')
  echo "LEARNINGS: $_LEARN_COUNT entries loaded"
  if [ "$_LEARN_COUNT" -gt 5 ] 2>/dev/null; then
    ~/.vibestack/bin/vibe-learnings-search --limit 5 2>/dev/null || true
  fi
else
  echo "LEARNINGS: none yet"
fi
```

{{include lib/snippets/session-host.md}}

{{include lib/snippets/decision-brief.md}}

{{include lib/snippets/working-protocols.md}}

{{include lib/snippets/state-protocols.md}}

# /setup-memory — Persistent Memory Setup

You are setting up persistent memory for this coding agent. The underlying engine
is secondbrain, a knowledge base that runs as both
a CLI and an MCP tool on the user's local Mac.

**Scope honesty:** This skill's MCP registration step (5a) uses
`claude mcp add` and targets Claude Code specifically. Other local hosts
(Cursor, Codex CLI, etc.) will still get the secondbrain CLI on PATH — they can
register `secondbrain serve` in their own MCP config manually after setup.

**Audience:** local-Mac users. openclaw/hermes agents typically run in cloud
docker containers with their own memory engine; "sharing" a brain between them
and local Claude Code is only possible through shared Postgres (Supabase).

## User-invocable
When the user types `/setup-memory`, run this skill. Three shortcut modes:

- `/setup-memory` — full flow (default)
- `/setup-memory --repo` — only flip the per-remote policy for the current repo
- `/setup-memory --switch` — only migrate the engine (PGLite ↔ Supabase)
- `/setup-memory --resume-provision ` — re-enter a previously interrupted
  Supabase auto-provision at the polling step
- `/setup-memory --cleanup-orphans` — list + delete in-flight Supabase projects

Parse the invocation args yourself — these are prose hints to the skill, not
implemented as a dispatcher binary.

---

## Concurrent-run lock

At skill start:
```bash
mkdir ~/.vibestack/.setup-memory.lock.d 2>/dev/null || {
  echo "Another /setup-memory instance is running. Wait for it, or remove the lock with:"
  echo "  rm -rf ~/.vibestack/.setup-memory.lock.d"
  exit 1
}
```

Release the lock on normal exit AND in the SIGINT trap.

---

## Step 1: Detect current state

```bash
SBRAIN_ON_PATH=false
SBRAIN_VERSION=""
SBRAIN_CONFIG_EXISTS=false
SBRAIN_ENGINE=""
SBRAIN_DOCTOR_OK=false
MEMORY_SYNC_MODE=""

command -v secondbrain >/dev/null 2>&1 && SBRAIN_ON_PATH=true
$SBRAIN_ON_PATH && SBRAIN_VERSION=$(secondbrain --version 2>/dev/null || echo "")
[ -f "$HOME/.secondbrain/config.json" ] && SBRAIN_CONFIG_EXISTS=true
if $SBRAIN_CONFIG_EXISTS; then
  SBRAIN_ENGINE=$(python3 -c "import json; d=json.load(open('$HOME/.secondbrain/config.json')); print(d.get('engine',''))" 2>/dev/null || echo "")
fi
if $SBRAIN_ON_PATH; then
  secondbrain doctor --json >/tmp/vibe-memory-doctor.json 2>/dev/null
  STATUS=$(python3 -c "import json; d=json.load(open('/tmp/vibe-memory-doctor.json')); print(d.get('status',''))" 2>/dev/null || echo "")
  [ "$STATUS" = "ok" ] || [ "$STATUS" = "warnings" ] && SBRAIN_DOCTOR_OK=true
fi
MEMORY_SYNC_MODE=$(vibe-config get memory_sync_mode 2>/dev/null || echo "")

echo "Detected: memory_engine=secondbrain on_path=$SBRAIN_ON_PATH version=${SBRAIN_VERSION:-none} engine=${SBRAIN_ENGINE:-none} doctor_ok=$SBRAIN_DOCTOR_OK sync=${MEMORY_SYNC_MODE:-off}"
```

Report the detected state in one line. Skip downstream steps that are already done.

Branch on the `--repo`, `--switch`, `--resume-provision`, `--cleanup-orphans`
invocation flags here and skip to the matching step.

Also capture `sbrain_local_status` (one of `ok`, `broken-db`, `broken-config`,
`no-cli`, `missing-config`), `sbrain_mcp_name` (the registered MCP name —
`memex`, `secondbrain`, or other compliant brand) and `sbrain_mcp_mode`
(`local-stdio`, `remote-http`, or empty) so Step 1.5 and Step 2 can branch on
them. Compute them inline:

```bash
SBRAIN_LOCAL_STATUS="ok"
if ! $SBRAIN_ON_PATH; then
  SBRAIN_LOCAL_STATUS="no-cli"
elif ! $SBRAIN_CONFIG_EXISTS; then
  SBRAIN_LOCAL_STATUS="missing-config"
elif ! $SBRAIN_DOCTOR_OK; then
  # Distinguish broken-db (config valid but engine unreachable) from broken-config
  # (config malformed). Falls back to broken-db if json parse worked at Step 1.
  if [ -n "$SBRAIN_ENGINE" ]; then SBRAIN_LOCAL_STATUS="broken-db"; else SBRAIN_LOCAL_STATUS="broken-config"; fi
fi
# Detect any compliant brain MCP — backend-agnostic per vibestack policy.
# `claude mcp list` lines look like:
#   memex: https://brain.example.com/mcp (HTTP) - ✓ Connected
#   secondbrain: /Users/foo/.bun/bin/secondbrain serve - ✓ Connected
# Match either name, strip the trailing colon, and infer mode from the (HTTP)
# marker. First match wins; downstream code should NOT assume the name is
# `secondbrain`.
_BRAIN_LINE=$(claude mcp list 2>/dev/null | awk '/^(memex|secondbrain):[[:space:]]/{print; exit}')
SBRAIN_MCP_NAME=$(printf '%s\n' "$_BRAIN_LINE" | awk '{name=$1; sub(/:$/, "", name); print name}')
SBRAIN_MCP_MODE=$(printf '%s\n' "$_BRAIN_LINE" | awk '{print (tolower($3)=="(http)")?"remote-http":"local-stdio"}')
[ -z "$_BRAIN_LINE" ] && SBRAIN_MCP_MODE=""
echo "sbrain_local_status=$SBRAIN_LOCAL_STATUS sbrain_mcp_name=${SBRAIN_MCP_NAME:-none} sbrain_mcp_mode=${SBRAIN_MCP_MODE:-none}"
```

---

## Step 1.5: Broken-local-engine remediation

If `SBRAIN_LOCAL_STATUS` is `broken-db` or `broken-config` AND no shortcut flag
was passed, the user has a non-working local engine (config exists but the
engine it points at isn't reachable, OR the config itself is malformed). Fire
a targeted AskUserQuestion BEFORE Step 2:

> D# — Your local secondbrain engine isn't responding. How do you want to fix it?
> Project/branch/task: 
> ELI10: secondbrain has a config at `~/.secondbrain/config.json` but the engine
> it points at isn't reachable. That could be a transient outage (Postgres container
> stopped, Tailscale down) OR a stale config you want to abandon. Different
> remediation for each case.
> Stakes if we pick wrong: "Switch to PGLite" overwrites your existing config
> (one-way door if the user actually wanted the broken engine). "Retry" preserves
> existing state for transient cases.
> Recommendation: A (Retry) — always try the cheap option first; if engine is
> just temporarily down it'll come back without any destructive change.
> Note: options differ in kind, not coverage — no completeness score.
> A) Retry — re-probe the engine (recommended; ~80ms)
>   ✅ Cheapest test: re-runs `secondbrain doctor --json` to see if engine is back
>   ✅ Zero side effects; existing config preserved
>   ❌ If engine is permanently dead, retries forever; user must choose another option
> B) Switch to local PGLite (one-way — moves existing config to .bak)
>   ✅ Fastest path to a working local engine if user has abandoned the old one
>   ✅ ~30s; no accounts; private to this machine
>   ❌ Destructive — existing config moved to ~/.secondbrain/config.json.vibestack-bak-{ts}
> C) Switch brain mode (continue to Step 2 path picker)
>   ✅ Lets user pick Path 1/2/3/4 to re-init from scratch
>   ✅ Preserves existing config until they explicitly init the new one
>   ❌ Longer flow if user just wants to repair to PGLite
> D) Quit (do nothing)
>   ✅ No cons — this is a hard-stop choice
>   ❌ N/A
> Net: A is the right starting move; B/C are explicit destructive paths; D bails.

**If A (Retry)**: re-run the detect block from Step 1. If the new
`sbrain_local_status` is `ok`, continue to Step 2. If still `broken-db` or
`broken-config`, fire the same AskUserQuestion again (the user picks again).

**If B (Switch to PGLite)** — execute the rollback-safe init sequence:

```bash
BACKUP="$HOME/.secondbrain/config.json.vibestack-bak-$(date +%s)"
mv "$HOME/.secondbrain/config.json" "$BACKUP"
if ! secondbrain init --pglite --json; then
  # Restore on failure
  mv "$BACKUP" "$HOME/.secondbrain/config.json"
  echo "secondbrain init failed. Your previous config was restored at $HOME/.secondbrain/config.json." >&2
  echo "PGLite directory at ~/.secondbrain/pglite/ may be in a partial state — \`rm -rf ~/.secondbrain/pglite\` if needed before retrying." >&2
  exit 1
fi
echo "Switched to local PGLite. Previous config saved at $BACKUP — review before deleting."
```

Then jump to Step 5a (MCP registration; the new PGLite engine is registered as
local-stdio).

**If C (Switch brain mode)**: continue to Step 2's normal path picker.

**If D (Quit)**: STOP the skill cleanly.

For `SBRAIN_LOCAL_STATUS` values of `no-cli` or `missing-config`, do NOT fire
Step 1.5 — fall through to Step 2 (where `no-cli` triggers Step 3 install and
`missing-config` triggers Step 4 init).

---

## Step 2: Pick a path (AskUserQuestion)

Only fire this if Step 1 shows no existing working config AND no shortcut
flag was passed. **Special case:** if `sbrain_mcp_mode=remote-http` in the
detect output (regardless of whether `sbrain_mcp_name` is `memex`,
`secondbrain`, or another compliant brand), an HTTP MCP brain is already
registered — skip directly to Step 5a verification (re-test the existing
registration under its detected name) and Step 6 onward, treating this run
as idempotent. Don't ask Step 2 again, and **never register a parallel
`secondbrain` entry pointing at the same URL** — that creates a duplicate
brain in `claude mcp list`.

The question title: "Where should your brain live?"

Options (present based on detected state):

- **1 — Supabase, I already have a connection string.** Cloud-agent users
  whose openclaw/hermes provisioned one already. Paste the Session Pooler
  URL from the Supabase dashboard (Settings → Database → Connection Pooler
  → Session). *Trust-surface caveat:* "Pasting this URL gives your local
  Claude Code full read/write access to every page your cloud agent can see.
  If that's not the trust level you want, pick PGLite local instead and
  accept the brains are disjoint."
- **2a — Supabase, auto-provision a new project.** You'll need a Supabase
  Personal Access Token (~90 seconds). Best choice for a shared team brain.
- **2b — Supabase, create manually.** Walk through supabase.com signup
  yourself; paste the URL back when ready.
- **3 — PGLite local.** Zero accounts, ~30 seconds. Isolated brain on this
  Mac only. Best for try-first.
- **4 — Remote secondbrain MCP.** Someone else (or another machine of yours) is
  already running `secondbrain serve` with HTTP transport. You paste the MCP URL
  + a bearer token; this skill registers it as your MCP. No local brain DB,
  no local install needed. Recommended when the brain is shared across
  machines or run by a teammate.
- **Switch** (only if Step 1 detected an existing engine): "You already have
  a `` brain. Migrate it to the other engine?" → runs
  `secondbrain migrate --to ` wrapped in `timeout 180s`.

Do NOT silently pick; fire the AskUserQuestion.

---

## Step 3: Install memory CLI (secondbrain)

**SKIP entirely on Path 4 (Remote MCP).** Path 4 doesn't need a local secondbrain
binary — all calls go through MCP to the remote server. Jump to Step 4 (the
Path 4 subsection).

For Paths 1, 2a, 2b, 3, switch — only if `SBRAIN_ON_PATH=false`:

```bash
# Try bun first, fall back to npm
if command -v bun >/dev/null 2>&1; then
  bun install -g secondbrain
elif command -v npm >/dev/null 2>&1; then
  npm install -g secondbrain
else
  echo "ERROR: Neither bun nor npm found. Install one first."
  exit 1
fi
```

After install, verify:
```bash
secondbrain --version
```

If `secondbrain --version` fails, check PATH:
```bash
# bun global bin
export PATH="$HOME/.bun/bin:$PATH"
secondbrain --version
```

If it still fails, surface the error and STOP — the environment is broken until
the user fixes PATH. Do not continue the skill.

**PATH-shadow validation.** Even when `secondbrain --version` succeeds, another
binary earlier on `$PATH` may be shadowing the one we just installed (a stale
global from a prior install, a colleague's fork checked into `~/bin/`, etc.).
Validate that the resolved `secondbrain` lives in the expected install
directory:

```bash
RESOLVED=$(command -v secondbrain)
EXPECTED_DIRS=("$HOME/.bun/install/global/node_modules/secondbrain" "$HOME/.npm/global/node_modules/secondbrain" "$(npm prefix -g 2>/dev/null)/lib/node_modules/secondbrain")
SHADOWED=true
for d in "${EXPECTED_DIRS[@]}"; do
  if printf '%s' "$RESOLVED" | grep -q "$(dirname "$d")"; then SHADOWED=false; break; fi
done
if $SHADOWED; then
  echo "WARN: \`secondbrain\` resolves to $RESOLVED, which is outside the expected global install paths."
  echo "      Another binary may be shadowing your install. Check \`type -a secondbrain\` and rearrange PATH if needed."
fi
```

The warning is non-blocking — the user may have intentionally installed a fork —
but surface it before continuing so half-broken setups don't get silently wired.

---

## Step 4: Initialize the brain

Path-specific.

### Path 1 (Supabase, existing URL)

Collect the URL securely (never as argv):

```bash
printf "Paste Session Pooler URL: "
read -rs SBRAIN_POOLER_URL
echo
printf "URL received (redacted): %s\n" "$(echo "$SBRAIN_POOLER_URL" | sed 's#://[^@]*@#://***@#')"
```

Validate structurally (must start with `postgresql://` and contain port 6543):

```bash
echo "$SBRAIN_POOLER_URL" | grep -qE '^postgresql://.+:6543/' || {
  echo "ERROR: URL does not look like a Session Pooler URL (expected port 6543)."
  echo "Get it from: Supabase dashboard → Settings → Database → Connection Pooler → Session"
  exit 1
}
```

On success, hand off to the memory CLI via env var (never argv):

```bash
export SBRAIN_DATABASE_URL="$SBRAIN_POOLER_URL"
secondbrain init --non-interactive --json
unset SBRAIN_POOLER_URL SBRAIN_DATABASE_URL
```

The URL is now persisted in `~/.secondbrain/config.json` at mode 0600 by the secondbrain CLI itself.

### Path 2a (Supabase, auto-provision)

Show the PAT scope disclosure BEFORE collecting the token:

> *This Supabase Personal Access Token grants full read/write/delete access
> to every project in your Supabase account, not just the `secondbrain` one we're
> about to create. Supabase doesn't currently support scoped tokens. We use
> this PAT only to: create one project, poll it until healthy, read the
> Session Pooler URL — then discard it from process memory. The token
> remains valid on Supabase's side until you manually revoke it at
> https://supabase.com/dashboard/account/tokens — we recommend revoking
> immediately after setup completes.*

Then collect securely:

```bash
printf "Paste PAT: "
read -rs SUPABASE_ACCESS_TOKEN
echo
export SUPABASE_ACCESS_TOKEN
```

Ask the tier prompt via AskUserQuestion: "Which Supabase tier?" Present
Free (2-project limit, pauses after 7d inactivity) vs Pro ($25/mo, no
pauses, recommended for real use). Explain that tier is **org-level** — user
picks their org based on its current tier.

List orgs:

```bash
curl -s -H "Authorization: Bearer $SUPABASE_ACCESS_TOKEN" \
  https://api.supabase.com/v1/organizations
```

If the orgs array is empty, surface: "Your Supabase account has no
organizations. Create one at https://supabase.com/dashboard, then re-run
`/setup-memory`." STOP.

If multiple orgs, use AskUserQuestion to pick one.

Ask the user for a region (default `us-east-1`).

Generate the DB password (never shown to the user):

```bash
export DB_PASS=$(openssl rand -base64 24)
```

Set up a SIGINT trap:

```bash
trap 'echo ""; echo "vibe-setup-memory: interrupted. In-flight ref: $INFLIGHT_REF"; \
      echo "Resume: /setup-memory --resume-provision $INFLIGHT_REF"; \
      echo "Delete: https://supabase.com/dashboard/project/$INFLIGHT_REF"; \
      unset SUPABASE_ACCESS_TOKEN DB_PASS; \
      rm -rf ~/.vibestack/.setup-memory.lock

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [timurgaleev](https://github.com/timurgaleev)
- **Source:** [timurgaleev/vibestack](https://github.com/timurgaleev/vibestack)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** yes
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-timurgaleev-vibestack-setup-memory
- Seller: https://agentstack.voostack.com/s/timurgaleev
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
