Skip to content
Back to skills

Settings

ASecurity

Configure agent settings — memory backend (builtin/QMD), search mode, temporal decay, citations. Triggers on /agent:settings, "configurar agente", "agent settings", "memory settings", "setup QMD", "configurar QMD", "configurar memoria".

  • 63 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added May 26, 2026
ai-agentsrustgoshellbashsqlnodegitapibackendsecurity

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned September 21, 2026

npx -y skills add crisandrews/ClawCode --skill settings --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Settings?

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

Security grade badge for Settings
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/crisandrews-settings/badge)](https://www.skillsdirectory.com/skills/crisandrews-settings)

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: settings
description: Configure agent settings — memory backend (builtin/QMD), search mode, temporal decay, citations. Triggers on /agent:settings, "configurar agente", "agent settings", "memory settings", "setup QMD", "configurar QMD", "configurar memoria".
user-invocable: true
argument-hint: [setting]
---

# Agent Settings

View and modify the agent's configuration stored in `agent-config.json`.

## Live voice integration

For ClaudeLive setup, ports, credentials, concurrency or disablement, use `/agent:live setup|status|disable` and its setup tools. Do not use the generic JSON-edit flow below for `liveBridge`; the Live helper preserves credentials and generates the matching launch environment.

## Show current settings

If no argument given, read and display `agent-config.json`:

```bash
cat ${CLAUDE_PLUGIN_ROOT}/agent-config.json 2>/dev/null || echo '(no config — using defaults)'
```

Show defaults:
- Memory backend: **builtin** (SQLite + FTS5 + BM25 + temporal decay + MMR)
- Citations: **auto**
- Temporal decay: **enabled** (half-life 30 days)
- MMR: **enabled** (lambda 0.7)
- Heartbeat: **every 30 min**, active hours 08:00-23:00
- Dreaming: **nightly at 3 AM**

## Available settings

### Memory backend: `builtin` or `qmd`

**builtin** (default):
- SQLite + FTS5 full-text search with BM25 ranking
- Temporal decay for dated files (older = less relevant)
- MMR diversity re-ranking
- Works out of the box, no external tools needed

**qmd** (enhanced):
- External tool by @tobi: https://github.com/tobi/qmd
- Local embeddings via node-llama-cpp (no API keys needed)
- Vector search with semantic understanding
- Reranking for better result quality
- Requires `qmd` binary installed

### Setting up QMD

1. **Check if qmd is installed:**
   ```bash
   qmd --version 2>/dev/null && echo "QMD available" || echo "QMD not found"
   ```

2. **If not installed, guide the user:**
   ```
   Install QMD (local-first search tool, no API keys needed):
   
   bun install -g qmd
   # or download from https://github.com/tobi/qmd/releases
   ```

3. **Configure the backend:**
   Write `agent-config.json` via Bash (NOT the `Write` tool — `agent-config.json` is on the always-on protected-paths list; direct `Write` is refused with `exec-gate: write to protected path refused (workspace-agent-config)`).

   **Step 3a — Read current config** with the `Read` tool: `Read("agent-config.json")`. If it doesn't exist, treat as `{}`.

   **Step 3b — Merge in-memory** in your reasoning: take the existing object, replace the `memory` key with the QMD block:
   ```json
   {
     "memory": {
       "backend": "qmd",
       "citations": "auto",
       "qmd": {
         "searchMode": "vsearch",
         "includeDefaultMemory": true,
         "limits": { "maxResults": 6, "timeoutMs": 15000 }
       }
     }
   }
   ```
   Preserve every other top-level key from the existing config.

   **Step 3c — Write the full merged object via Bash heredoc with validate + atomic mv** (substitute `<FULL_MERGED_JSON>` with the JSON literal from your reasoning):
   ```
   Bash('cat > agent-config.json.tmp << "JSON_EOF" &&
   <FULL_MERGED_JSON>
   JSON_EOF
   node -e \'JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"))\' agent-config.json.tmp \
     && mv agent-config.json.tmp agent-config.json \
     && echo "wrote agent-config.json" \
     || { rm -f agent-config.json.tmp; echo "ABORTED: invalid JSON or filesystem error"; exit 1; }')
   ```

   The user gets ONE Bash permission prompt. By design — `agent-config.json` controls security-sensitive settings, so writes go through deliberate user consent. The `"JSON_EOF"` (double-quoted delimiter) form disables shell expansion inside the body, so any literal `$` or backtick in the JSON stays untouched. `cat > ... << "JSON_EOF" &&` puts the heredoc write itself in the `&&` chain so a `cat` failure short-circuits the rest (otherwise a `cat` that fails to open the tmp file would leave any pre-existing tmp content intact, `node` would validate stale content, and `mv` would clobber the destination with old data). The `node -e 'JSON.parse(...)'` step rejects malformed JSON before the atomic `mv` — your existing config can never be clobbered by a truncated or syntactically broken write.

4. **If qmd is in a non-standard path**, set the command:
   ```json
   "qmd": {
     "command": "/path/to/qmd",
     ...
   }
   ```

5. **Reload the MCP server:**
   ```
   /mcp
   ```

### Search modes (QMD only)

| Mode | Description | Speed | Quality |
|---|---|---|---|
| `search` | Basic vector + BM25 hybrid | Fast | Good |
| `vsearch` | Vector search with reranking | Medium | Excellent |
| `query` | Full query expansion + rerank | Slow | Best |

Default: `vsearch` (recommended).

### Temporal decay (builtin only)

Controls how dated files (memory/YYYY-MM-DD.md) lose relevance over time:
- `halfLifeDays: 30` — a 30-day-old file scores at 50% of a today's file
- Set to a larger number (e.g., 90) to keep older memories relevant longer
- Set `temporalDecay: false` to disable

### Citations

- `auto` — show citations in direct chats, suppress in groups
- `on` — always show
- `off` — never show

## Modifying settings

To change a setting:
1. Read current `agent-config.json` with the `Read` tool (or treat as `{}` if it doesn't exist).
2. Compute the full updated object IN YOUR REASONING — preserve every other top-level key, only change the field(s) the user asked about.
3. Write back via Bash heredoc with validate + atomic mv (NOT the `Write` tool — `agent-config.json` is on the always-on protected-paths list; direct `Write` is refused). Substitute `<FULL_UPDATED_JSON>` with your computed object:
   ```
   Bash('cat > agent-config.json.tmp << "JSON_EOF" &&
   <FULL_UPDATED_JSON>
   JSON_EOF
   node -e \'JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"))\' agent-config.json.tmp \
     && mv agent-config.json.tmp agent-config.json \
     && echo "wrote agent-config.json" \
     || { rm -f agent-config.json.tmp; echo "ABORTED: invalid JSON or filesystem error"; exit 1; }')
   ```
   The double-quoted `"JSON_EOF"` delimiter disables shell expansion in the body — JSON literals pass through verbatim, no escaping needed. `cat > ... << "JSON_EOF" &&` puts the heredoc write itself in the `&&` chain so a `cat` failure short-circuits the rest. The `node -e 'JSON.parse(...)'` step rejects malformed JSON BEFORE the atomic `mv`, so a truncated or syntactically broken write can never clobber your config.
4. Run `/mcp` to apply.

## Heartbeat settings

### Active hours
Restrict heartbeat to the user's active window:
```json
{
  "heartbeat": {
    "schedule": "*/30 * * * *",
    "activeHours": {
      "start": "08:00",
      "end": "23:00",
      "timezone": "America/Santiago"
    }
  }
}
```

Outside these hours, the heartbeat cron still fires but the agent should skip silently.

### Dreaming schedule
```json
{
  "dreaming": {
    "schedule": "0 3 * * *",
    "timezone": "America/Santiago"
  }
}
```

## HTTP bridge + WebChat (optional)

The HTTP bridge is an optional local server that exposes the agent over HTTP — for webhooks, status checks, and a browser-based chat UI (WebChat).

**Off by default.** Enable with:

```json
{
  "http": {
    "enabled": true,
    "port": 18790,
    "host": "127.0.0.1",
    "token": ""
  }
}
```

Settings:
- `enabled` — turn the server on/off (default: `false`)
- `port` — port to listen on (default: `18790`)
- `host` — bind address (default: `127.0.0.1` — localhost only; change only if you know what you're doing)
- `token` — Bearer token for authenticated endpoints. Empty = no auth (fine for localhost-only). Set a value when exposing via tunnel (ngrok, Cloudflare, Tailscale).

### Using WebChat

1. Enable the HTTP bridge (above).
2. Run `/mcp` to reload.
3. Open `http://localhost:18790` in a browser.
4. Type. The agent sees messages as real user input — personality, memory, and commands all work the same as in WhatsApp or the CLI.

Endpoints exposed when `http.enabled: true`:
- `GET /` — WebChat UI
- `GET /health` — liveness (no auth)
- `GET /v1/status` — agent status
- `GET /v1/skills` — installed skills
- `POST /v1/webhook` — ingest webhooks
- `GET /v1/webhooks` — drain webhook queue
- `POST /v1/chat/send` — send a chat message
- `GET /v1/chat/history` — chat history
- `GET /v1/chat/stream` — real-time replies (SSE)

To turn WebChat off without losing other HTTP features, just close the browser tab. To turn the whole bridge off, set `http.enabled: false` and run `/mcp`.

### Security note

Bind to `127.0.0.1` unless you know your network is safe. If you must expose the port (LAN, tunnel), always set a `token` — otherwise anyone who can reach the port can chat as you.

## Channel scope (`scope.*`) — secondary access point

The full UX for channel-scope is `/agent:scope wizard` (interactive). `/agent:settings` provides a read-only secondary view of the current `scope.*` config and pointers to the wizard for changes.

To inspect:

```bash
node -e "const c=JSON.parse(require('fs').readFileSync('agent-config.json','utf-8'));console.log(JSON.stringify(c.scope||{},null,2));"
```

Display each configured channel:

- `mode`: `off` (default — no filter) / `shadow` (log only) / `enforce` (filter)
- `identity`: `auto` (default ceiling) / `owner` (sees all — requires out-of-band trust file) / `guest` (sees nothing channel-derived)
- `background.identity`: `deny` (default — dreams don't see scoped chunks) / `system-owner` (dreams see as owner)

**Cannot modify scope.* via `agent_config(action='set')`** — any key starting with `scope.` is on the security-sensitive blocklist. Use `/agent:scope wizard` or `/agent:scope enable <channel> [shadow|enforce]` instead — those routes go through `Bash` so the user gets a permission prompt for every scope-policy change.

Full feature description: `docs/channel-scope-compat.md` · `PRIVACY.md#channel-scope-per-channel-opt-in`.

## Important

- After any config change, the user must run `/mcp` to reload
- The builtin backend is always available as fallback even when QMD is configured
- QMD first run downloads embedding models (~100MB) — this is a one-time cost
- Heartbeat active hours are enforced by the agent (instructions), not the cron system
- Channel-scope (`scope.*`) keys are read-only via `agent_config` — use `/agent:scope wizard` for any changes (security-sensitive blocklist routes scope-policy changes through Bash for explicit user consent)

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.