Skip to content
Back to skills

Run App

ASecurity

Launch NodeSpace (daemon + dev-proxy + frontend) and drive it in a browser to see a change working in the real app. Use when asked to run, start, or screenshot the app, or to confirm a change works outside the test suite.

  • 8 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 20, 2026
ai-agentsrustshellbashsqlnodeapidatabasefrontend

Works with

  • cli
  • api
  • mcp

Security analysis

A93/100
  • highPerforms destructive filesystem operations

Pro shows the line behind each finding and how to fix it

Scanned October 6, 2026

npx -y skills add NodeSpaceAI/nodespace-core --skill run-app --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Run App?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Run App
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/nodespaceai-run-app/badge)](https://www.skillsdirectory.com/skills/nodespaceai-run-app)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: run-app
description: Launch NodeSpace (daemon + dev-proxy + frontend) and drive it in a browser to see a change working in the real app. Use when asked to run, start, or screenshot the app, or to confirm a change works outside the test suite.
allowed-tools: Bash, Read, Write, Edit
---

## What this skill is for

Running the real app — daemon, dev-proxy and frontend — so you can look at
actual rendered nodes. Use it when tests pass but you need to *see* something:
a visual change, a layout, an interaction.

## CRITICAL: never launch the daemon against the user's real database

The daemon defaults to `~/.nodespace/database/nodespace.db` — the user's actual
notes. Two traps, both of which have bitten before:

1. **A bare `nodespaced` starts a daemon against the real database.**
   `nodespaced --help` does not print help. A binary built from a current
   checkout refuses any argument other than `--tray` and `--version` with a
   one-line error and exit status 2 before anything starts, but an older one
   (the installed `/usr/local/bin` or Homebrew daemon, or a stale
   `target/debug/nodespaced` that step 1 reuses) ignores unknown flags and
   starts serving. Do not probe a binary you did not just build. The flags are
   constants in `packages/daemon/src/main.rs`; the environment variables it
   honours are resolved in `packages/daemon/src/lib.rs`.
2. **`NODESPACED_DB_PATH` alone is not isolation.** The source says so directly
   (`resolve_db_path` doc comment): setting it while inheriting the real home
   "would seed the real `~/.nodespace/databases.toml` with a throwaway path
   (ADR-053)". Observed behavior: the daemon still served the real DB.

**`NODESPACE_HOME` is the correct lever.** It relocates the whole state
directory — database, registry and embedding model — in one variable. Chat
models still load from `$HOME`. Provider settings and API keys are fields of
each database's own settings node (ADR-095), so an isolated daemon's database
starts with none; to test against a provider, add it in the isolated database
(the Settings screen, or the settings node's typed update), never by copying a
real database over it.

## Launch sequence

Run every step from the repo (or worktree) root.

### 1. Build the daemon if needed

```bash
ls target/debug/nodespaced || bun run build:sidecars --debug
```

A fresh worktree has no binary. `build:sidecars --debug` produces it (several
minutes cold).

### 2. Start the daemon on an isolated home + SHORT socket path

```bash
mkdir -p /tmp/nsd && rm -f /tmp/nsd/d.sock
NODESPACE_HOME=<scratchpad>/nshome \
NODESPACED_SOCKET=/tmp/nsd/d.sock \
  ./target/debug/nodespaced > <scratchpad>/daemon.log 2>&1
```

Run it with `run_in_background: true`.

**The socket path must be short.** Unix sockets cap at `SUN_LEN` (~104 chars),
and a session scratchpad path alone can exceed it. The failure is explicit:

```
Error: Failed to bind Unix socket: ...
Caused by: path must be shorter than SUN_LEN
```

So: **database** under the scratchpad (isolated), **socket** under `/tmp/nsd`
(short). They do not have to be co-located.

The isolated home holds no embedding model, so the daemon starts with semantic
search off and puts nothing on the GPU. To check a change that needs semantic
search, add `NODESPACED_MODEL_PATH=$HOME/.nodespace/models/nomic-embed-text-v1.5.Q8_0.gguf`,
which loads the model onto the GPU.

Wait for readiness with an `until` loop, not a fixed sleep — first boot seeds
~37 agent roots:

```bash
until [ -S /tmp/nsd/d.sock ] || grep -qiE "^Error|panic" <scratchpad>/daemon.log; do sleep 1; done
grep -iE "serving default database|gRPC server listening|^Error" <scratchpad>/daemon.log | tail -3
```

**Confirm the log line says the scratch path, not `/Users/<you>/.nodespace/`.**
That one line is the check that isolation worked.

### 3. Start the frontend pointed at the same socket

```bash
NODESPACED_SOCKET=/tmp/nsd/d.sock bun run dev:browser > <scratchpad>/dev.log 2>&1
```

Background it. `dev:browser` runs the dev-proxy (:3001) and Vite (:5173)
together. **The socket variable must match the daemon's** — the proxy defaults
to `~/.nodespace/daemon.sock` and will sit at "Connecting to local service…"
forever if it points somewhere else.

```bash
until curl -s -o /dev/null http://localhost:5173/; do sleep 1; done
curl -s -o /dev/null -w "proxy: HTTP %{http_code}\n" http://localhost:3001/health
```

Both up = the full chain (frontend → proxy → gRPC → daemon → SQLite) is live.

### 4. Drive it

Navigate to `http://localhost:5173/` with Playwright. A scratch DB opens on
today's Daily Journal with one empty node.

"Connecting to local service…" plus zero nodes means the daemon is not
reachable — fix that rather than working around it. Injecting your own markup
tests your markup, not the app.

Create nodes by typing into the real textarea:

```js
const ta = page.locator('textarea.node__content').first();
await ta.click();
await ta.pressSequentially('A text node', { delay: 5 });
await page.keyboard.press('Enter');
```

Markdown prefixes (`# `, `[] `, `> `, `1. `) change node type, but typing them
fast races the input handler and mangles the text. Add `waitForTimeout(400)`
between nodes, and do not trust the resulting text — for visual checks the
garbled text is usually irrelevant, but do not report it as correct content.

Routes are a dead end: the root layout renders the app shell for every path, so
a temporary `+page.svelte` never mounts.

### 5. Toggle themes

`.dark` / `.light` live on `documentElement`:

```js
document.documentElement.classList.remove('dark');
document.documentElement.classList.add('light');
```

Always check both — light-mode-only verification misses the case where
something inherits `--foreground` and turns near-white on dark.

### 6. Clean up

Stop both background tasks, then:

```bash
rm -rf /tmp/nsd
pgrep -fl "nodespaced|dev-proxy"     # expect nothing
ls -la ~/.nodespace/database/nodespace.db   # mtime must predate your session
```

Delete stray screenshots and `.playwright-mcp/` from the repo before
committing.

## Reading colors accurately

Computed values beat eyeballing a screenshot. Measure on a real rendered
element:

```js
getComputedStyle(document.querySelector('.node-icon svg circle:last-of-type')).fill
```

A probe element resolves a variable without needing a rendered node:

```js
const p = document.createElement('div');
document.body.appendChild(p);
p.style.color = 'hsl(var(--node-text))';
const v = getComputedStyle(p).color;
p.remove();
```

## Quick reference

| Thing | Value |
|---|---|
| Isolation lever | `NODESPACE_HOME` (**not** `NODESPACED_DB_PATH` alone) |
| Socket var | `NODESPACED_SOCKET`, same value for daemon and proxy |
| Socket path | Must be short — `/tmp/nsd/d.sock`, never the scratchpad |
| Headless | Default — tray mode needs `--tray` |
| Ports | Vite 5173, dev-proxy 3001 |
| Real DB (never touch) | `~/.nodespace/database/nodespace.db` |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.