{"id":"add-emacs","name":"add-emacs","summary":"Emacsをチャンネルに追加してください。インタラクティブなチャットバッファと組織モードの統合が開き、Emacs(Doom、Spacemacs、またはバニラ)内からNanoClawと話すことができます。","body":"# Add Emacs Channel\n\nAdds Emacs support via a local HTTP bridge. Works with Doom Emacs, Spacemacs, and vanilla Emacs 27.1+.\n\n## What you can do with this\n\n- **Ask while coding** — open the chat buffer (`C-c n c` / `SPC N c`), ask about a function or error without leaving Emacs\n- **Code review** — select a region and send it with `nanoclaw-org-send`; the response appears as a child heading inline in your org file\n- **Meeting notes** — send an org agenda entry; get a summary or action item list back as a child node\n- **Draft writing** — send org prose; receive revisions or continuations in place\n- **Research capture** — ask a question directly in your org notes; the answer lands exactly where you need it\n\n## Install\n\nNanoClaw doesn't ship channels in trunk. This skill copies the Emacs adapter and the Lisp client in from the `channels` branch. Native HTTP bridge — no Chat SDK, no adapter package.\n\n### 1. Copy the adapter and Lisp client\n\nFetch the `channels` branch from the configured remote that carries it, then\noverwrite the skill-owned files with the canonical registry copies:\n\n```nc:copy from-branch:channels\nsrc/channels/emacs.ts\nsrc/channels/emacs.test.ts\nsrc/channels/emacs-registration.test.ts\nemacs/nanoclaw.el\n```\n\n### 2. Append the self-registration import\n\nAppend to `src/channels/index.ts` (skip if the line is already present):\n\n```nc:append to:src/channels/index.ts\nimport './emacs.js';\n```\n\n### 3. Build and validate\n\n```nc:run effect:build\npnpm run build\n```\n```nc:run effect:test\npnpm exec vitest run src/channels/emacs-registration.test.ts\n```\n\nBoth must be clean before proceeding. `emacs-registration.test.ts` is the one integration test: it imports the real channel barrel and asserts the registry contains `emacs`. It goes red if the `import './emacs.js';` line is deleted or drifts, or if the barrel fails to evaluate (so the channel genuinely would not register). The adapter uses only Node builtins (`http`), so there is no npm dependency to guard for this channel.\n\nEnd-to-end message delivery from a real Emacs buffer is verified manually once the service is running — see Verify and Troubleshooting.\n\n## Enable\n\nThe adapter is gated by `EMACS_ENABLED` so the HTTP port isn't opened on hosts that aren't running Emacs. Add to `.env`:\n\n```bash\nEMACS_ENABLED=true\nEMACS_CHANNEL_PORT=8766       # optional — change only if 8766 is taken\nEMACS_AUTH_TOKEN=             # optional — set to a random string to lock the endpoint\nEMACS_PLATFORM_ID=default     # optional — only change if you want a non-default chat id\n```\n\nGenerate an auth token (recommended even on single-user machines — prevents other local processes from poking the endpoint):\n\n```bash\nnode -e \"console.log(require('crypto').randomBytes(16).toString('hex'))\"\n```\n\n## Wire the channel\n\nEmacs is a single-user, single-chat channel. One host = one messaging group with `platform_id = \"default\"`.\n\n### If this is your first agent group\n\nRun `/init-first-agent` — pick **Emacs** as the channel, use any short handle as the \"user id\" (e.g. your OS username), and the skill will create the agent group, wire the channel, and write a welcome message that the agent delivers back to your Emacs buffer.\n\n### Otherwise — wire to an existing agent group\n\nRun the `register` step directly. The `EMACS_PLATFORM_ID` (default `default`) becomes the messaging group's platform id:\n\n```bash\npnpm exec tsx setup/index.ts --step register -- \\\n  --platform-id \"default\" --name \"Emacs\" \\\n  --folder \"<existing-folder>\" --channel \"emacs\" \\\n  --session-mode \"agent-shared\" \\\n  --assistant-name \"<existing-assistant-name>\"\n```\n\n`agent-shared` puts Emacs messages in the same session as any other channel wired to the same agent group — so a conversation you started in Telegram continues in Emacs. Use `shared` to keep an independent Emacs thread with the same workspace, or a new `--folder` for a dedicated Emacs-only agent.\n\nAlternatively create the rows with `ncl` — **the host service must be running** (`ncl` connects to it over a Unix socket). Engage mode/pattern and `unknown_sender_policy` default to the Emacs adapter's declared channel defaults:\n\n```bash\nncl messaging-groups create --channel-type emacs --platform-id \"default\" --name \"Emacs\"\nncl wirings create --messaging-group-id <mg-id-from-above> --agent-group-id <ag-id> \\\n  --session-mode agent-shared\n```\n\n## Configure Emacs\n\n`nanoclaw.el` needs only Emacs 27.1+ builtins (`url`, `json`, `org`) — no package manager.\n\nAskUserQuestion: Which Emacs distribution are you using?\n- **Doom Emacs** — `config.el` with `map!` keybindings\n- **Spacemacs** — `dotspacemacs/user-config` in `~/.spacemacs`\n- **Vanilla Emacs / other** — `init.el` with `global-set-key`\n\n**Doom Emacs** — add to `~/.config/doom/config.el` (or `~/.doom.d/config.el`):\n\n```elisp\n;; NanoClaw — personal AI assistant channel\n(load (expand-file-name \"~/src/nanoclaw/emacs/nanoclaw.el\"))\n\n(map! :leader\n      :prefix (\"N\" . \"NanoClaw\")\n      :desc \"Chat buffer\"  \"c\" #'nanoclaw-chat\n      :desc \"Send org\"     \"o\" #'nanoclaw-org-send)\n```\n\nReload: `M-x doom/reload`\n\n**Spacemacs** — add to `dotspacemacs/user-config` in `~/.spacemacs`:\n\n```elisp\n;; NanoClaw — personal AI assistant channel\n(load-file \"~/src/nanoclaw/emacs/nanoclaw.el\")\n\n(spacemacs/set-leader-keys \"aNc\" #'nanoclaw-chat)\n(spacemacs/set-leader-keys \"aNo\" #'nanoclaw-org-send)\n```\n\nReload: `M-x dotspacemacs/sync-configuration-layers` or restart Emacs.\n\n**Vanilla Emacs** — add to `~/.emacs.d/init.el`:\n\n```elisp\n;; NanoClaw — personal AI assistant channel\n(load-file \"~/src/nanoclaw/emacs/nanoclaw.el\")\n\n(global-set-key (kbd \"C-c n c\") #'nanoclaw-chat)\n(global-set-key (kbd \"C-c n o\") #'nanoclaw-org-send)\n```\n\nReload: `M-x eval-buffer` or restart Emacs.\n\nReplace `~/src/nanoclaw/emacs/nanoclaw.el` with your actual NanoClaw checkout path.\n\nIf `EMACS_AUTH_TOKEN` is set, also add (any distribution):\n\n```elisp\n(setq nanoclaw-auth-token \"<your-token>\")\n```\n\nIf you changed `EMACS_CHANNEL_PORT` from the default:\n\n```elisp\n(setq nanoclaw-port <your-port>)\n```\n\n## Restart NanoClaw\n\nRun from your NanoClaw project root:\n\n```bash\npnpm run build\nsource setup/lib/install-slug.sh\nlaunchctl kickstart -k gui/$(id -u)/$(launchd_label)   # macOS\n# systemctl --user restart $(systemd_unit)             # Linux\n```\n\n## Verify\n\n### HTTP endpoint\n\n```bash\ncurl -s http://localhost:8766/api/messages?since=0\n```\n\nExpected: `{\"messages\":[]}`. With an auth token:\n\n```bash\ncurl -s -H \"Authorization: Bearer <token>\" http://localhost:8766/api/messages?since=0\n```\n\n### From Emacs\n\nTell the user:\n\n> 1. Open the chat buffer with your keybinding (`SPC N c`, `SPC a N c`, or `C-c n c`)\n> 2. Type a message and press `C-c C-c` to send (RET inserts newlines)\n> 3. A response should appear within a few seconds\n>\n> For org-mode: open any `.org` file, position the cursor on a heading, and use `SPC N o` / `SPC a N o` / `C-c n o`\n\n### Log line\n\n`tail -f logs/nanoclaw.log` should show `Emacs channel listening` at startup.\n\n## Channel Info\n\n- **type**: `emacs`\n- **terminology**: Single local buffer. There are no \"groups\" or separate chats — one host = one chat, addressed by a `platform_id` string (default `default`).\n- **how-to-find-id**: The platform id is whatever you set in `EMACS_PLATFORM_ID` (default `default`). User handles are arbitrary; your OS username or first name is fine (e.g. `emacs:<username>`).\n- **supports-threads**: no\n- **typical-use**: Single developer talking to the assistant from within Emacs, alongside whatever other channel they use (Slack, Telegram, Discord).\n- **default-isolation**: Same agent group as the primary DM, with `session-mode = agent-shared` so a conversation started elsewhere continues in Emacs. Pick a separate folder only if you specifically want an Emacs-only persona.\n\n### Features\n\n- Interactive chat buffer (`nanoclaw-chat`) with markdown → org-mode rendering\n- Org integration (`nanoclaw-org-send`) — sends the current subtree or region; reply lands as a child heading\n- Optional bearer-token auth for the local endpoint\n- Single-user: the adapter exposes exactly one messaging group per host\n\nNot applicable (design): multi-user channels, threads, cold DM initiation, typing indicators, attachments.\n\n## Troubleshooting\n\n### Port already in use\n\n```\nError: listen EADDRINUSE: address already in use :::8766\n```\n\nEither a stale NanoClaw is running or another app has the port. Kill stale process or change port:\n\n```bash\nlsof -ti :8766 | xargs kill -9\n# or set EMACS_CHANNEL_PORT in .env and mirror in Emacs config (nanoclaw-port)\n```\n\n### Adapter not starting\n\nIf `grep \"Emacs channel listening\" logs/nanoclaw.log` returns nothing, check that `EMACS_ENABLED=true` is in `.env` and that the adapter import is present:\n\n```bash\ngrep -q '^EMACS_ENABLED=true' .env && echo \"enabled\" || echo \"not enabled\"\ngrep -q \"import './emacs.js'\" src/channels/index.ts && echo \"imported\" || echo \"not imported\"\n```\n\n### No response from agent\n\n1. NanoClaw running: `launchctl list | grep \"$(. setup/lib/install-slug.sh && launchd_label)\"` (macOS) / `systemctl --user status \"$(. setup/lib/install-slug.sh && systemd_unit)\"` (Linux)\n2. Messaging group wired: `pnpm exec tsx scripts/q.ts data/v2.db \"SELECT mg.platform_id, ag.folder FROM messaging_groups mg JOIN messaging_group_agents mga ON mg.id = mga.messaging_group_id JOIN agent_groups ag ON ag.id = mga.agent_group_id WHERE mg.channel_type = 'emacs'\"`\n3. Logs show inbound: `grep 'channel_type=emacs\\|Emacs' logs/nanoclaw.log | tail -20`\n\nIf no messaging group row exists, run the `register` command above.\n\n### Auth token mismatch (401 Unauthorized)\n\n```elisp\nM-x describe-variable RET nanoclaw-auth-token RET\n```\n\nMust match `EMACS_AUTH_TOKEN` in `.env`. If you didn't set one server-side, clear it in Emacs too:\n\n```elisp\n(setq nanoclaw-auth-token nil)\n```\n\n### nanoclaw.el not loading\n\n```bash\nls ~/src/nanoclaw/emacs/nanoclaw.el\n```\n\nIf NanoClaw is cloned elsewhere, update the `load`/`load-file` path in your Emacs config.\n\n## Agent Formatting\n\nThe Emacs bridge converts markdown → org-mode automatically. Agents should output standard markdown, **not** org-mode syntax:\n\n| Markdown | Org-mode |\n|----------|----------|\n| `**bold**` | `*bold*` |\n| `*italic*` | `/italic/` |\n| `~~text~~` | `+text+` |\n| `` `code` `` | `~code~` |\n| ` ```lang ` | `#+begin_src lang` |\n\nIf an agent outputs org-mode directly, markers get double-converted and render incorrectly.\n\n## Removal\n\nSee [REMOVE.md](REMOVE.md) to uninstall this channel.","author":"@nanocoai","ownerProfile":null,"authorContacts":null,"sourceUrl":"https://github.com/nanocoai/nanoclaw/tree/main/.claude/skills/add-emacs","license":"MIT","category":"writing","lang":"en","tokens":2788,"stars":0,"calls30d":1,"claimed":false,"visibility":"public","origin":"crawler","version":"0.1.0","createdAt":"2026-08-22","updatedAt":"2026-08-22","files":[{"path":"REMOVE.md","size":1419,"sha256":"296a28d933c86069c3006abb71af9ae981c116cc0fadb17d297123b6176ad6ac"}],"requires":{"mcp":[],"tools":[]},"safety":{"flags":[],"scannedAt":"2026-08-22","hasScripts":false,"networkEndpoints":[]}}