NanoClaw 原始碼解讀:用極簡架構打造安全的個人 AI 助理

NanoClaw 是一個只有幾個核心檔案的個人 Claude 助理,透過 WhatsApp 與你對話,每次對話都在獨立的 Linux Container 中執行。它的設計哲學直接挑戰了「功能越多越好」的常見思維——整個系統只有一個 Node.js process、一個 SQLite 資料庫、一個 polling loop,卻實現了多群組隔離、排程任務、檔案系統安全等企業級功能。讀完這份原始碼,你會學到如何用 Container 隔離取代應用層權限檢查、如何透過 filesystem-based IPC 讓沙箱內的 agent 與外界安全通訊,以及「Skills over Features」的 AI-native 擴展模式。

NanoClaw GitHub Repository — 專案原始碼,包含本文解讀的所有設計實作

專案概覽

NanoClaw 是一個運行在 macOS/Linux 上的個人 Claude 助理。使用者透過 WhatsApp 傳送訊息,系統將訊息路由到 Claude Agent SDK,在 Apple Container 或 Docker 容器中執行 agent 回覆。

技術棧:TypeScript / Node.js、SQLite(better-sqlite3)、WhatsApp Web(baileys)、Claude Agent SDK、Apple Container / Docker

規模:核心 host process 僅 8 個 TypeScript 檔案(src/ 目錄),容器內 agent runner 僅 2 個檔案。整個 codebase 的邏輯程式碼不超過 1500 行。

架構總覽

WhatsApp (baileys) ──▶ SQLite ──▶ Polling Loop ──▶ Container (Claude Agent SDK) ──▶ Response
                                                        │
                                                        ▼
                                                  IPC via Filesystem
                                                        │
                                                        ▼
                                              Host 處理 messages/tasks
nanoclaw/
├── src/                        # Host process(全部核心邏輯)
│   ├── index.ts                # 入口:WhatsApp 連線、訊息路由、IPC watcher
│   ├── container-runner.ts     # 容器生命週期:mount 組裝、spawn、輸出解析
│   ├── db.ts                   # SQLite schema 與所有查詢
│   ├── task-scheduler.ts       # 排程任務引擎
│   ├── mount-security.ts       # 掛載安全驗證(allowlist 機制)
│   ├── config.ts               # 常數與環境變數
│   ├── types.ts                # TypeScript 型別定義
│   └── utils.ts                # JSON 讀寫工具
├── container/                  # 容器映像
│   ├── Dockerfile              # Agent 執行環境
│   └── agent-runner/src/       # 容器內程式碼
│       ├── index.ts            # Agent 啟動器(Claude Agent SDK query)
│       └── ipc-mcp.ts          # MCP Server:agent 的對外通訊介面
├── groups/                     # 每個群組的隔離記憶空間
│   ├── main/CLAUDE.md          # 主頻道 prompt(有管理員權限)
│   └── global/CLAUDE.md        # 全域共享 prompt
└── .claude/skills/             # Claude Code Skills(擴展機制)
    ├── setup/SKILL.md
    ├── customize/SKILL.md
    ├── debug/SKILL.md
    └── add-gmail/SKILL.md
Code language: PHP (php)

核心設計解析

設計一:Single Process + Polling Loop 取代事件驅動架構

NanoClaw 的核心是一個極為簡單的 polling loop:每 2 秒從 SQLite 撈取新訊息,依序處理。這個設計刻意避開了 event-driven 架構的複雜度。

src/index.ts — 主入口,包含訊息路由、WhatsApp 連線和 IPC watcher 三大核心邏輯

async function startMessageLoop(): Promise<void> {
  if (messageLoopRunning) {
    logger.debug('Message loop already running, skipping duplicate start');
    return;
  }
  messageLoopRunning = true;

  while (true) {
    try {
      const jids = Object.keys(registeredGroups);
      const { messages } = getNewMessages(jids, lastTimestamp, ASSISTANT_NAME);

      for (const msg of messages) {
        try {
          await processMessage(msg);
          // Only advance timestamp after successful processing for at-least-once delivery
          lastTimestamp = msg.timestamp;
          saveState();
        } catch (err) {
          logger.error({ err, msg: msg.id }, 'Error processing message, will retry');
          break;  // Stop processing this batch - failed message will be retried next loop
        }
      }
    } catch (err) {
      logger.error({ err }, 'Error in message loop');
    }
    await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL));
  }
}
Code language: JavaScript (javascript)

這段程式碼中有幾個值得注意的設計決策:

  1. At-least-once deliverylastTimestamp 只在訊息成功處理後才前進。如果處理失敗,下次 loop 會重試同一則訊息。
  2. Guard flag 防止重複啟動messageLoopRunning 確保 WhatsApp 重連時不會產生多個 polling loop。
  3. Sequential processing:訊息嚴格依序處理,break 中斷整個 batch 而非跳過失敗訊息——保證訊息順序。

這種「笨方法」的可靠性遠高於複雜的 message queue 系統,因為狀態機非常簡單:只有一個 timestamp 和一個 while loop。

設計二:Container 隔離作為主要安全邊界

NanoClaw 最核心的設計理念是:安全不靠應用層權限檢查,靠 OS 級隔離。每次 agent 執行都在一個全新的 Container 中,只有明確 mount 的目錄才對 agent 可見。

src/container-runner.ts — 容器生命週期管理,組裝 volume mounts 並 spawn 容器 process

function buildVolumeMounts(
  group: RegisteredGroup,
  isMain: boolean,
): VolumeMount[] {
  const mounts: VolumeMount[] = [];

  if (isMain) {
    // Main gets the entire project root mounted
    mounts.push({
      hostPath: projectRoot,
      containerPath: '/workspace/project',
      readonly: false,
    });
    mounts.push({
      hostPath: path.join(GROUPS_DIR, group.folder),
      containerPath: '/workspace/group',
      readonly: false,
    });
  } else {
    // Other groups only get their own folder
    mounts.push({
      hostPath: path.join(GROUPS_DIR, group.folder),
      containerPath: '/workspace/group',
      readonly: false,
    });
    // Global memory directory (read-only for non-main)
    const globalDir = path.join(GROUPS_DIR, 'global');
    if (fs.existsSync(globalDir)) {
      mounts.push({
        hostPath: globalDir,
        containerPath: '/workspace/global',
        readonly: true,
      });
    }
  }

  // Per-group IPC namespace: each group gets its own IPC directory
  const groupIpcDir = path.join(DATA_DIR, 'ipc', group.folder);
  mounts.push({
    hostPath: groupIpcDir,
    containerPath: '/workspace/ipc',
    readonly: false,
  });
  // ...
}

這裡的設計差異非常鮮明:

  • Main group:掛載整個專案目錄,有完整讀寫權限——因為它是使用者自己的 self-chat,是 trusted
  • Non-main groups:只能看到自己的資料夾和 read-only 的全域記憶——因為群組中可能有其他人,是 untrusted
  • IPC 目錄按群組隔離:每個群組有自己的 /workspace/ipc,無法跨群組通訊

這個分層信任模型不需要任何應用層的 if (user.hasPermission(...)) 檢查。Agent 在容器裡想做什麼都行——但它的世界就只有那幾個 mount point。

設計三:Filesystem-based IPC——讓沙箱 Agent 安全地與外界通訊

Container 內的 agent 無法直接存取 host 上的 WhatsApp 連線或 SQLite 資料庫。NanoClaw 設計了一套基於 filesystem 的 IPC 協議:agent 將操作寫成 JSON 檔案到 IPC 目錄,host process 定期掃描並執行。

container/agent-runner/src/ipc-mcp.ts — 容器內的 MCP Server,將 agent 的操作意圖序列化為 JSON 檔案

function writeIpcFile(dir: string, data: object): string {
  fs.mkdirSync(dir, { recursive: true });
  const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}.json`;
  const filepath = path.join(dir, filename);

  // Atomic write: temp file then rename
  const tempPath = `${filepath}.tmp`;
  fs.writeFileSync(tempPath, JSON.stringify(data, null, 2));
  fs.renameSync(tempPath, filepath);
  return filename;
}
Code language: JavaScript (javascript)

而 host 端的 IPC watcher 會驗證每個操作的授權:

src/index.ts — IPC watcher 以群組目錄名稱為身份識別,驗證操作授權

// Authorization: verify this group can send to this chatJid
const targetGroup = registeredGroups[data.chatJid];
if (isMain || (targetGroup && targetGroup.folder === sourceGroup)) {
  await sendMessage(data.chatJid, `${ASSISTANT_NAME}: ${data.text}`);
} else {
  logger.warn(
    { chatJid: data.chatJid, sourceGroup },
    'Unauthorized IPC message attempt blocked',
  );
}
Code language: JavaScript (javascript)

這個設計的精妙之處在於:群組的身份不由 IPC payload 決定,而由 IPC 目錄路徑決定。因為每個群組的 IPC 目錄是分開 mount 的,agent 無法偽造身份——它只能寫入 /workspace/ipc,而 host 知道這個目錄對應哪個群組。

設計四:Sentinel Markers 解決容器輸出解析問題

Container 的 stdout 裡混合了 agent 的 debug log 和最終結果。NanoClaw 用一對「哨兵標記」來可靠地提取 JSON 輸出:

src/container-runner.ts — 用 sentinel markers 從混雜的 stdout 中精確提取結構化輸出

const OUTPUT_START_MARKER = '---NANOCLAW_OUTPUT_START---';
const OUTPUT_END_MARKER = '---NANOCLAW_OUTPUT_END---';

// Extract JSON between sentinel markers for robust parsing
const startIdx = stdout.indexOf(OUTPUT_START_MARKER);
const endIdx = stdout.indexOf(OUTPUT_END_MARKER);

let jsonLine: string;
if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
  jsonLine = stdout.slice(startIdx + OUTPUT_START_MARKER.length, endIdx).trim();
} else {
  // Fallback: last non-empty line (backwards compatibility)
  const lines = stdout.trim().split('\n');
  jsonLine = lines[lines.length - 1];
}

const output: ContainerOutput = JSON.parse(jsonLine);
Code language: JavaScript (javascript)

這是一個務實的工程決策:與其要求容器內所有 log 走 stderr(很難控制第三方庫的行為),不如在 stdout 中用明確的界線標記來區分「雜訊」和「訊號」。同時保留了 fallback 機制確保向後相容。

設計五:外部 Allowlist 的掛載安全模型

NanoClaw 的 mount security 設計了一個防篡改機制:allowlist 存放在 ~/.config/nanoclaw/mount-allowlist.json——在專案目錄之外,永遠不會被 mount 進任何容器。

src/mount-security.ts — 掛載安全驗證,包含 symlink 解析、blocked patterns 和多層授權邏輯

const DEFAULT_BLOCKED_PATTERNS = [
  '.ssh', '.gnupg', '.gpg', '.aws', '.azure', '.gcloud',
  '.kube', '.docker', 'credentials', '.env', '.netrc',
  '.npmrc', '.pypirc', 'id_rsa', 'id_ed25519',
  'private_key', '.secret',
];
Code language: JavaScript (javascript)
function findAllowedRoot(realPath: string, allowedRoots: AllowedRoot[]): AllowedRoot | null {
  for (const root of allowedRoots) {
    const expandedRoot = expandPath(root.path);
    const realRoot = getRealPath(expandedRoot);
    if (realRoot === null) continue;

    // Check if realPath is under realRoot
    const relative = path.relative(realRoot, realPath);
    if (!relative.startsWith('..') && !path.isAbsolute(relative)) {
      return root;
    }
  }
  return null;
}
Code language: JavaScript (javascript)

驗證流程有三層防護:

  1. Blocked patterns:無論設定如何,.ssh.env 等敏感路徑永遠被阻擋
  2. Symlink resolution:用 fs.realpathSync() 解析真實路徑,防止 symlink traversal attack
  3. Allowed roots:只有在允許的根目錄下的路徑才能被 mount
  4. Non-main read-only:非主群組的額外掛載強制為 read-only

這個設計的核心原則是:安全設定放在 agent 不可觸及的地方

設計六:MCP Server 作為 Agent 的能力邊界

容器內的 agent 透過 Claude Agent SDK 的 MCP(Model Context Protocol)機制獲得能力。NanoClaw 用 createSdkMcpServer 定義了一組精心設計的工具:

container/agent-runner/src/ipc-mcp.ts — 定義 agent 可用的 MCP tools,每個 tool 都帶有詳細的使用指引

export function createIpcMcp(ctx: IpcMcpContext) {
  return createSdkMcpServer({
    name: 'nanoclaw',
    version: '1.0.0',
    tools: [
      tool('send_message', 'Send a message to the current WhatsApp group...', {
        text: z.string().describe('The message text to send')
      }, async (args) => {
        const data = { type: 'message', chatJid, text: args.text, ... };
        const filename = writeIpcFile(MESSAGES_DIR, data);
        return { content: [{ type: 'text', text: `Message queued for delivery (${filename})` }] };
      }),

      tool('schedule_task',
        `Schedule a recurring or one-time task...
         CONTEXT MODE - Choose based on task type:
         • "group": Task runs in the group's conversation context...
         • "isolated": Task runs in a fresh session...`,
        { prompt: z.string(), schedule_type: z.enum(['cron', 'interval', 'once']), ... },
        async (args) => { /* validation + IPC write */ }
      ),
      // list_tasks, pause_task, resume_task, cancel_task, register_group...
    ]
  });
}
Code language: JavaScript (javascript)

注意 schedule_task 工具的 description 有多長——它包含了 context mode 的選擇指引、cron 表達式格式說明、時區處理注意事項。這些 description 本質上是寫給 Claude 看的「使用手冊」,直接影響 agent 的行為品質。

而 agent runner 的 allowedTools 設定精確控制了 agent 可用的能力:

container/agent-runner/src/index.ts — Agent 啟動邏輯,配置 Claude Agent SDK 的 query 參數

for await (const message of query({
  prompt,
  options: {
    cwd: '/workspace/group',
    resume: input.sessionId,
    allowedTools: [
      'Bash', 'Read', 'Write', 'Edit', 'Glob', 'Grep',
      'WebSearch', 'WebFetch',
      'mcp__nanoclaw__*'
    ],
    permissionMode: 'bypassPermissions',
    allowDangerouslySkipPermissions: true,
    settingSources: ['project'],
    mcpServers: { nanoclaw: ipcMcp },
    hooks: { PreCompact: [{ hooks: [createPreCompactHook()] }] }
  }
})) { ... }
Code language: JavaScript (javascript)

bypassPermissions + allowDangerouslySkipPermissions 看起來很危險——但因為 agent 在容器內,Bash 命令只能影響容器環境。這是「Container 隔離取代權限檢查」理念的直接體現。

設計七:PreCompact Hook 實現對話記憶歸檔

NanoClaw 利用 Claude Agent SDK 的 Hook 機制,在對話被壓縮前自動歸檔完整 transcript:

container/agent-runner/src/index.ts — PreCompact Hook 將完整對話歸檔為 Markdown 檔案

function createPreCompactHook(): HookCallback {
  return async (input, _toolUseId, _context) => {
    const preCompact = input as PreCompactHookInput;
    const transcriptPath = preCompact.transcript_path;

    if (!transcriptPath || !fs.existsSync(transcriptPath)) return {};

    const content = fs.readFileSync(transcriptPath, 'utf-8');
    const messages = parseTranscript(content);

    const summary = getSessionSummary(sessionId, transcriptPath);
    const name = summary ? sanitizeFilename(summary) : generateFallbackName();

    const conversationsDir = '/workspace/group/conversations';
    fs.mkdirSync(conversationsDir, { recursive: true });

    const date = new Date().toISOString().split('T')[0];
    const filename = `${date}-${name}.md`;
    fs.writeFileSync(filePath, markdown);
    return {};
  };
}
Code language: JavaScript (javascript)

這解決了一個實際問題:Claude 的 context window 有限,長對話會被壓縮摘要。但使用者可能想回顧完整對話內容。PreCompact Hook 在壓縮觸發前將完整對話以 Markdown 格式存檔,未來可被 agent 搜索。

設計八:Per-Group CLAUDE.md 作為 Agent Persona 與記憶

每個群組有自己的 CLAUDE.md,agent 在該群組的容器中以此為 system prompt。這是 NanoClaw 的「記憶」機制:

groups/global/CLAUDE.md — 全域 prompt,定義 agent 基礎人格與行為規範

# Andy

You are Andy, a personal assistant...

## Long Tasks
If a request requires significant work, use `mcp__nanoclaw__send_message` to acknowledge first:
1. Send a brief message: what you understood and what you'll do
2. Do the work
3. Exit with the final answer

## Memory
The `conversations/` folder contains searchable history of past conversations.
When you learn something important:
- Create files for structured data (e.g., `customers.md`, `preferences.md`)
- Add recurring context directly to this CLAUDE.md
Code language: PHP (php)

groups/main/CLAUDE.md — 主頻道 prompt,包含管理員特權指引和群組管理操作流程

主群組的 CLAUDE.md 則額外包含管理員操作指引——如何查詢可用群組、如何註冊新群組、如何設定額外的目錄掛載。這些「操作手冊」直接寫在 prompt 裡,agent 就「知道」如何執行管理任務。

這個設計讓 NanoClaw 的「設定檔」就是自然語言。想改變 agent 行為?直接修改 CLAUDE.md。想讓 agent 記住某件事?告訴它「remember this」。

設計九:Skills over Features——以 Skill 檔案取代 Feature Branch

NanoClaw 最大膽的設計決策是:不接受新功能的 PR,只接受 Skill 的 PR

.claude/skills/customize/SKILL.md — Customize skill,教 Claude Code 如何互動式地修改 NanoClaw 的行為

---
name: customize
description: Add new capabilities or modify NanoClaw behavior...
---

# NanoClaw Customization

## Key Files
| File | Purpose |
|------|---------|
| `src/config.ts` | Assistant name, trigger pattern, directories |
| `src/index.ts` | Message routing, WhatsApp connection, agent invocation |

## Common Customization Patterns

### Adding a New Input Channel (e.g., Telegram, Slack, Email)

Questions to ask:
- Which channel?
- Same trigger word or different?
- Same memory hierarchy or separate?

Implementation pattern:
1. Find/add MCP server for the channel
2. Add connection and message handling in `src/index.ts`
3. Store messages in the database
4. Ensure responses route back to correct channel
Code language: PHP (php)

Skill 不是程式碼,而是教 Claude Code 如何修改程式碼的指引。使用者執行 /add-telegram,Claude Code 讀取 Skill 文件,然後直接修改使用者 fork 中的程式碼。最終每個使用者的 codebase 只包含他們真正需要的功能——沒有 Telegram 程式碼殘留在一個只用 WhatsApp 的系統中。

設計十:Credential Filtering 與最小權限暴露

容器需要 Claude API 認證才能執行,但 NanoClaw 不會把整個 .env 給容器:

src/container-runner.ts — 只過濾出 agent 需要的環境變數,以 read-only 方式掛載

const envContent = fs.readFileSync(envFile, 'utf-8');
const allowedVars = ['CLAUDE_CODE_OAUTH_TOKEN', 'ANTHROPIC_API_KEY'];
const filteredLines = envContent.split('\n').filter((line) => {
  const trimmed = line.trim();
  if (!trimmed || trimmed.startsWith('#')) return false;
  return allowedVars.some((v) => trimmed.startsWith(`${v}=`));
});

if (filteredLines.length > 0) {
  fs.writeFileSync(path.join(envDir, 'env'), filteredLines.join('\n') + '\n');
  mounts.push({
    hostPath: envDir,
    containerPath: '/workspace/env-dir',
    readonly: true,
  });
}
Code language: JavaScript (javascript)

注意是 readonly: true——容器不能修改認證資訊。而 Dockerfile 中的 entrypoint 負責從這個目錄讀取環境變數:

container/Dockerfile — 容器映像定義,entrypoint 從 mount 目錄載入環境變數

# Sources env from mounted /workspace/env-dir/env if it exists
# (workaround for Apple Container -i bug)
[ -f /workspace/env-dir/env ] && export $(cat /workspace/env-dir/env | xargs)
Code language: PHP (php)

SECURITY.md 坦誠地指出目前的限制:agent 在容器內仍可透過 Bash 讀取這些認證。這種「承認限制並標記為待改進」的態度,比假裝問題不存在更負責任。

Prompt 設計解讀

NanoClaw 的 prompt 設計體現了「分層特權」的理念。全域 CLAUDE.md 定義基礎行為,主群組的 CLAUDE.md 則額外授予管理能力。

groups/main/CLAUDE.md — 主頻道的 prompt 設計,包含結構化的管理操作指引

幾個值得學習的 prompt 設計技巧:

  1. 明確的能力宣告:prompt 開頭就列出「What You Can Do」,讓 agent 清楚知道自己的能力邊界
  2. 操作流程寫成步驟:「Adding a Group」分成 6 個明確步驟,避免 agent 遺漏操作
  3. Fallback 策略:查詢群組時先用 IPC 檔案,如果找不到再查 SQLite——直接把 fallback 邏輯寫進 prompt
  4. 格式約束:「Do NOT use markdown headings (##) in WhatsApp messages」——避免 agent 使用 WhatsApp 不支援的格式
  5. 長任務處理:「先用 send_message 回覆確認,再做事,再回覆結果」——避免使用者等待無回應

MCP tool 的 description 同樣是精心設計的 prompt:

tool('schedule_task',
  `...CONTEXT MODE - Choose based on task type:
   • "group" (recommended for most tasks): Task runs in the group's conversation context...
   • "isolated": Task runs in a fresh session...

   If unsure which mode to use, ask the user. Examples:
   - "Remind me about our discussion" → group (needs conversation context)
   - "Check the weather every morning" → isolated (self-contained task)`,
  ...
)
Code language: JavaScript (javascript)

透過具體的 examples 引導 Claude 在模糊場景中做出正確選擇。

設計理念萃取

  • Container 隔離優於應用層權限 — 與其在程式碼中寫一堆 if (hasPermission) 檢查,不如讓安全邊界在 OS 層面。Agent 在沙箱裡可以 bypassPermissions,因為它的世界只有你允許它看到的部分。這個模式適用於任何需要執行不受信任程式碼的場景。
  • Filesystem-based IPC 適合跨信任邊界通訊 — 當兩個 process 處於不同信任等級時,用 JSON 檔案作為 IPC 比 socket 更容易審計和控制。原子寫入(temp file + rename)保證了可靠性,而目錄路徑作為身份識別避免了身份偽造。
  • Prompt 就是設定檔 — NanoClaw 沒有 YAML 設定、沒有 admin dashboard。行為變更直接寫在 CLAUDE.md 中,用自然語言描述。這在 AI-native 應用中是合理的——你的「使用者」是 LLM,自然語言就是最好的設定語言。
  • Skills over Features 是 AI 時代的新擴展模式 — 不把所有功能塞進一個 codebase,而是用 Skill 文件教 AI 如何按需修改程式碼。每個使用者的 fork 只包含他們真正需要的功能,不存在功能膨脹問題。
  • 極簡架構的可維護性紅利 — 8 個核心檔案、1500 行程式碼,任何人(或 AI)都能在 8 分鐘內理解整個系統。這種「小到可以理解」的設計哲學,讓 debug、customization 和安全審計都變得可行。

延伸思考

NanoClaw 的設計模式可以延伸到許多場景:

AI Agent 安全沙箱:如果你在構建任何需要執行 AI 生成程式碼的系統,Container 隔離 + mount allowlist 的模式比 application-level sandboxing 更可靠。關鍵是把安全設定放在 agent 不可觸及的地方。

Multi-tenant Agent 系統:per-group 隔離的模式——獨立的 filesystem、session、IPC namespace——可以直接應用到 SaaS 產品中的 multi-tenant AI agent 架構。信任等級不同的 tenant 就給不同的 mount 權限。

AI-native Configuration:如果你的系統主要由 AI 操作,考慮用自然語言文件(如 CLAUDE.md)取代傳統設定檔。這不只是「方便」——LLM 理解自然語言的能力遠超理解 YAML 語法,行為的可預測性反而更高。

Skills 模式:對於任何面向開發者的 CLI 工具或框架,可以考慮用「教 AI 如何修改程式碼」的 Skill 文件來取代 plugin system。使用者得到的是乾淨的、量身定制的程式碼,而不是一堆可能衝突的 plugin。

Vibe Coding:把觀念變成程式碼

以下是你可以直接給 AI 的 prompt 指令,將本文介紹的設計觀念應用到你的專案中:

Container 隔離取代應用層權限檢查

場景:你正在設計一個需要執行不受信任程式碼的系統(AI agent、使用者提交的程式碼、自動化腳本),目前用應用層的 if (hasPermission) 來控制存取權限。

給 AI 的指令

我的系統需要執行不受信任的程式碼,目前用應用層權限檢查來控制安全。我想改用 NanoClaw 的「Container 隔離作為主要安全邊界」模式——把每次執行放進獨立的 Docker Container,用 volume mount 來控制可見範圍,而不是在程式碼中寫權限判斷。

請幫我設計一個 container-runner 模組,需要:
1. 根據使用者的信任等級組裝不同的 volume mounts(例如:管理員掛載整個專案目錄可讀寫、一般使用者只掛載自己的資料夾)
2. 敏感路徑(.ssh、.env、credentials)無論設定如何都不能被掛載——實作一個 blocked patterns 清單
3. 所有路徑都要做 symlink resolution(fs.realpathSync),防止 symlink traversal attack
4. 環境變數只傳遞白名單中的項目,且以 read-only 方式掛載

我的技術棧是 [你的語言/框架],容器技術用 [Docker/Podman]。

效果:AI 會產出一個完整的 container runner 模組,包含 volume mount 組裝邏輯、blocked patterns 安全檢查、symlink 解析驗證,以及環境變數過濾機制。你的安全邊界會從分散在各處的 if 判斷,變成集中在 OS 層級的隔離。

Filesystem-based IPC 跨信任邊界通訊

場景:你有兩個不同信任等級的 process 需要通訊(例如沙箱中的 agent 需要觸發 host 上的操作),正在考慮用 socket、HTTP API、或 message queue。

給 AI 的指令

我的系統中有一個在 Container 沙箱內執行的 agent process,它需要請求 host process 執行某些操作(例如發送訊息、排程任務),但不能直接存取 host 的資源。

我想採用 NanoClaw 的「Filesystem-based IPC」模式:agent 將操作意圖序列化為 JSON 檔案寫入共享的 IPC 目錄,host process 定期掃描這個目錄並執行。請幫我實作:
1. IPC 寫入端:用 atomic write(先寫 temp file 再 rename)保證檔案完整性,檔名用 timestamp + random string 確保唯一
2. IPC 讀取端:host 的 watcher 定期掃描目錄,解析 JSON,根據目錄路徑識別來源身份(不信任 payload 中的身份宣告),處理完後刪除或歸檔檔案
3. 授權驗證:host 根據 IPC 檔案所在的目錄路徑(而非檔案內容)判斷請求者身份,確保無法偽造身份

我的技術棧是 [你的語言/框架]。

效果:AI 會產出 IPC 的寫入端和讀取端程式碼,包含原子寫入、目錄掃描、身份驗證邏輯。這種模式比 socket 更容易審計(檔案系統留下完整痕跡),比 HTTP API 更安全(不需要暴露 port)。

Sentinel Markers 解決混合輸出解析

場景:你的系統需要從子 process 的 stdout 中提取結構化輸出,但 stdout 裡混雜了各種 debug log、第三方庫的輸出,讓 JSON 解析經常失敗。

給 AI 的指令

我的系統會 spawn 子 process 並需要從 stdout 中提取 JSON 結果,但 stdout 裡混合了 debug log 和第三方庫的輸出,無法直接 JSON.parse 整個 stdout。

請幫我實作 NanoClaw 的「Sentinel Markers」模式:
1. 定義一對唯一的標記字串(例如 ---MY_OUTPUT_START------MY_OUTPUT_END---),子 process 在輸出結果前後印出這對標記
2. 父 process 從 stdout 中用 indexOf 找到標記,提取中間的 JSON 內容
3. 加上 fallback 機制:如果找不到標記,嘗試解析最後一行非空行(向後相容)
4. 加上錯誤處理:標記找到但 JSON 解析失敗的情況

請同時給我子 process 端的輸出函式和父 process 端的解析函式。

效果:AI 會產出一對配合使用的函式——子 process 端的 emitResult() 和父 process 端的 parseContainerOutput(),包含 sentinel markers、fallback 邏輯和完整的錯誤處理。

Skills over Features 擴展模式

場景:你在維護一個開源專案或內部工具,想讓使用者能自訂功能,但不希望所有功能都塞進同一個 codebase(造成功能膨脹)。

給 AI 的指令

我想為我的專案 [專案名稱] 採用 NanoClaw 的「Skills over Features」擴展模式——不直接加功能到 codebase,而是寫 SKILL.md 文件教 AI 如何按需修改使用者 fork 中的程式碼。

請幫我為以下功能寫一個 SKILL.md 檔案:[要新增的功能描述]

SKILL.md 的格式參考:
– YAML frontmatter 包含 name 和 description
– 列出相關的 Key Files 和它們的用途
– 列出互動式問題(AI 應該先問使用者什麼?)
– 寫出具體的 Implementation Pattern(步驟化的修改指引)
– 包含注意事項和常見陷阱

目標是讓使用者執行這個 Skill 後,AI 能根據指引直接修改程式碼,而不是安裝一個 plugin。

效果:AI 會產出一個結構化的 SKILL.md 檔案,包含完整的互動流程和實作步驟。使用者可以把這個 Skill 加入 .claude/skills/ 目錄,讓 Claude Code 根據指引自動化地修改程式碼。

Prompt 作為設定檔的 AI-native 設計

場景:你正在開發一個 AI agent 應用,需要讓不同的使用者/租戶有不同的行為設定,目前用 YAML 或 JSON 設定檔。

給 AI 的指令

我正在開發一個多租戶的 AI agent 系統,目前每個租戶的行為設定用 JSON 設定檔管理。我想改用 NanoClaw 的「Prompt 就是設定檔」模式——每個租戶有自己的 CLAUDE.md(或類似的 system prompt 文件),用自然語言定義 agent 的行為、能力和限制。

請幫我設計這個 prompt-as-config 架構:
1. 設計 prompt 的分層結構:全域 prompt(所有租戶共享的基礎行為)+ 租戶專屬 prompt(個別客製)
2. 全域 prompt 範本:包含能力宣告、長任務處理流程(先確認再執行再回報)、格式約束、fallback 策略
3. 租戶 prompt 範本:包含該租戶特有的知識、偏好、可用工具清單
4. prompt 載入機制:agent 啟動時按優先順序合併這些 prompt

我的 agent 使用 [Claude API / OpenAI API / 其他]。

效果:AI 會產出一套 prompt 範本和載入機制,讓你用自然語言文件取代 JSON 設定檔。當需要調整 agent 行為時,直接修改 markdown 文件而非程式碼。

延伸閱讀

0

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *