feat!: move slack-formatting container skill to the channels branch

Same treatment as whatsapp-formatting (previous commit): slack-formatting
is channel payload, not trunk. It ships only a SKILL.md (no composed-doc
fragment) and reaches agents via ~/.claude/skills; /add-slack and the
slack setup installers now copy it from the channels branch, which
already carries an identical copy. Changelog entry combined for both.

BREAKING CHANGE: existing Slack installs lose the slack-formatting skill
from ~/.claude/skills after updating; re-run /add-slack (idempotent).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A2YZQDTw9TQrH3m8NBtVAW
This commit is contained in:
gavrielc
2026-07-10 22:45:23 +03:00
parent b9998a4bf1
commit cb2bbcc7aa
7 changed files with 20 additions and 98 deletions
+8
View File
@@ -18,6 +18,7 @@ Skip to **Credentials** if all of these are already in place:
- `src/channels/slack.ts` exists
- `src/channels/slack-registration.test.ts` exists
- `src/channels/index.ts` contains `import './slack.js';`
- `container/skills/slack-formatting/SKILL.md` exists
- `@chat-adapter/slack` is listed in `package.json` dependencies
Otherwise continue. Every step below is safe to re-run.
@@ -33,8 +34,15 @@ git fetch origin channels
```bash
git show origin/channels:src/channels/slack.ts > src/channels/slack.ts
git show origin/channels:src/channels/slack-registration.test.ts > src/channels/slack-registration.test.ts
mkdir -p container/skills/slack-formatting
git show origin/channels:container/skills/slack-formatting/SKILL.md > container/skills/slack-formatting/SKILL.md
```
The `slack-formatting` container skill is part of the channel payload: it
reaches agents via `~/.claude/skills` (synced at spawn) and teaches Slack's
mrkdwn syntax. Trunk does not ship it — without this copy step agents send
Slack messages with generic markdown that renders literally.
### 3. Append the self-registration import
Append to `src/channels/index.ts` (skip if the line is already present):
+1 -1
View File
@@ -4,7 +4,7 @@ All notable changes to NanoClaw will be documented in this file.
## [Unreleased]
- [BREAKING] **`whatsapp-formatting` container skill moved out of trunk — WhatsApp installs must re-run `/add-whatsapp` after updating.** The skill (`container/skills/whatsapp-formatting/`) now lives on the `channels` branch as part of the WhatsApp payload and is copied in by `/add-whatsapp` and the setup channel installers; trunk no longer ships it, so non-WhatsApp installs stop carrying WhatsApp formatting instructions in every agent's composed CLAUDE.md. **Existing WhatsApp installs:** updating removes the skill from your working tree, and the next container spawn regenerates each group's CLAUDE.md without the `skill-whatsapp-formatting.md` fragment — agents will silently lose WhatsApp formatting rules (asterisk bold, no headers, etc.) until you re-run `/add-whatsapp` (idempotent; it now restores the skill) or copy it back directly: `mkdir -p container/skills/whatsapp-formatting && git show origin/channels:container/skills/whatsapp-formatting/SKILL.md > container/skills/whatsapp-formatting/SKILL.md && git show origin/channels:container/skills/whatsapp-formatting/instructions.md > container/skills/whatsapp-formatting/instructions.md`.
- [BREAKING] **Channel formatting skills (`whatsapp-formatting`, `slack-formatting`) moved out of trunk — WhatsApp and Slack installs must re-run their `/add-<channel>` skill after updating.** Both skills now live on the `channels` branch as part of their channel's payload and are copied in by `/add-whatsapp` / `/add-slack` and the setup channel installers; trunk no longer ships them, so installs without those channels stop carrying channel-specific formatting instructions in every agent's context. **Existing installs:** updating removes the skills from your working tree. For WhatsApp, the next container spawn also regenerates each group's composed CLAUDE.md without the `skill-whatsapp-formatting.md` fragment — agents silently lose WhatsApp formatting rules (asterisk bold, no headers, etc.). For Slack, the `slack-formatting` skill drops out of `~/.claude/skills`, so agents lose the mrkdwn guidance. Re-run `/add-whatsapp` and/or `/add-slack` (idempotent; they now restore the skills), or copy back directly, e.g. `mkdir -p container/skills/whatsapp-formatting && git show origin/channels:container/skills/whatsapp-formatting/instructions.md > container/skills/whatsapp-formatting/instructions.md` (plus the sibling `SKILL.md`, and `container/skills/slack-formatting/SKILL.md` for Slack).
- **Pre-task script failures back their series off instead of spinning.** A `--script` that errors lands the occurrence as a failed run (`script-skip:error` ack → `failed` status); recurrence reads the series' trailing failed streak and re-arms at `max(cron next, now + 2·2^(n1) min, cap 60)`; after 8 consecutive failures the series is auto-paused with a host-written note in its run log (`ncl tasks resume` revives it). A deliberate `wakeAgent:false` gate is a normal run and never backs off. Also fixed: an explicitly-addressed `<message to>` in a task fire's final text now delivers as a deliberate send (previously suppressed as a turn-reply echo → zero delivery when the agent skipped the MCP tool); identical echoes of an MCP send are dropped in the runner, where the duplication originates.
- [BREAKING] **Scheduled tasks moved from MCP tools to `ncl tasks`.** The six scheduling MCP tools are no longer exposed to agent containers; agents and operators manage tasks with `ncl tasks list/get/create/update/cancel/pause/resume/delete`. New tasks run from a per-agent-group system session rather than waking the chat session that created them, and task writes are not approval-gated inside the owning group. **Migration:** [docs/ncl-tasks-migration.md](docs/ncl-tasks-migration.md).
- **Optional per-container resource caps.** `CONTAINER_CPU_LIMIT` and `CONTAINER_MEMORY_LIMIT` pass through to `docker run` as `--cpus` / `--memory` (`container-runner.ts`). Both empty by default — no flag added, spawn args byte-identical to today — so existing installs are unaffected. Set them to cap an agent container's CPU/memory so one agent can't monopolize the host (e.g. `CONTAINER_CPU_LIMIT=2`, `CONTAINER_MEMORY_LIMIT=8g`). Swap is intentionally not managed here: `--memory` is a hard cap on a swapless host.
+2 -2
View File
@@ -79,7 +79,7 @@ For ad-hoc queries from skills or scripts, use the in-tree wrapper rather than t
| `src/channels/` | Channel adapter infra (registry, Chat SDK bridge); specific channel adapters are skill-installed from the `channels` branch |
| `src/providers/` | Host-side provider container-config (`claude` baked in; `opencode` etc. installed from the `providers` branch) |
| `container/agent-runner/src/` | Agent-runner: poll loop, formatter, provider abstraction, MCP tools, destinations |
| `container/skills/` | Container skills mounted into every agent session (`agent-browser`, `frontend-engineer`, `onecli-gateway`, `self-customize`, `slack-formatting`, `vercel-cli`, `welcome`; channel-specific skills like `whatsapp-formatting` install with their channel) |
| `container/skills/` | Container skills mounted into every agent session (`agent-browser`, `frontend-engineer`, `onecli-gateway`, `self-customize`, `vercel-cli`, `welcome`; channel-specific skills like `slack-formatting` and `whatsapp-formatting` install with their channel) |
| `groups/<folder>/` | Per-agent-group filesystem (CLAUDE.md, skills) — agent-runner source is a shared read-only mount, not copied per group |
| `scripts/init-first-agent.ts` | Bootstrap the first DM-wired agent (used by `/init-first-agent` skill) |
| `migrate-v2.sh` + `setup/migrate-v2/` | v1→v2 migration. Standalone script: `bash migrate-v2.sh`. Seeds DB, copies groups/sessions, installs channels, builds container, offers service switchover, then hands off to `/migrate-from-v1` skill for owner setup and CLAUDE.md cleanup. See [docs/migration-dev.md](docs/migration-dev.md). |
@@ -183,7 +183,7 @@ Four types of skills. See [CONTRIBUTING.md](CONTRIBUTING.md) for the full taxono
- **Channel/provider install skills** — copy the relevant module(s) in from the `channels` or `providers` branch, wire imports, install pinned deps (e.g. `/add-discord`, `/add-slack`, `/add-whatsapp`, `/add-opencode`).
- **Utility skills** — ship code files alongside `SKILL.md` (e.g. a `scripts/` CLI or helper).
- **Operational skills** — instruction-only workflows (`/setup`, `/debug`, `/customize`, `/init-first-agent`, `/manage-channels`, `/init-onecli`, `/update-nanoclaw`).
- **Container skills** — loaded inside agent containers at runtime (`container/skills/`: `agent-browser`, `frontend-engineer`, `onecli-gateway`, `self-customize`, `slack-formatting`, `vercel-cli`, `welcome`; channel-specific skills like `whatsapp-formatting` are copied in by their `/add-<channel>` skill).
- **Container skills** — loaded inside agent containers at runtime (`container/skills/`: `agent-browser`, `frontend-engineer`, `onecli-gateway`, `self-customize`, `vercel-cli`, `welcome`; channel-specific skills like `slack-formatting` and `whatsapp-formatting` are copied in by their `/add-<channel>` skill).
| Skill | When to Use |
|-------|-------------|
+1 -1
View File
@@ -92,7 +92,7 @@ Skills that run inside the agent container, not on the host. These teach the Nan
**Location:** `container/skills/<name>/`
**Examples:** `agent-browser` (web browsing), `frontend-engineer`, `onecli-gateway` (OneCLI proxy usage), `self-customize`, `slack-formatting` (Slack mrkdwn syntax), `vercel-cli`, `welcome`, `whatsapp-formatting` (channels branch; installed by `/add-whatsapp`)
**Examples:** `agent-browser` (web browsing), `frontend-engineer`, `onecli-gateway` (OneCLI proxy usage), `self-customize`, `vercel-cli`, `welcome`; channel-specific: `slack-formatting` (Slack mrkdwn syntax) and `whatsapp-formatting` (channels branch; installed by `/add-slack` / `/add-whatsapp`)
**Key difference:** You never invoke these from a coding-agent session on the host, the way you run `/setup` or `/update-nanoclaw` in Claude Code/Codex/OpenCode. They're mounted into the sandbox and loaded by the NanoClaw agent itself, shaping how it behaves when you chat with it.
@@ -1,94 +0,0 @@
---
name: slack-formatting
description: Format messages for Slack using mrkdwn syntax. Use when responding to Slack channels (folder starts with "slack_" or JID contains slack identifiers).
---
# Slack Message Formatting (mrkdwn)
When responding to Slack channels, use Slack's mrkdwn syntax instead of standard Markdown.
## How to detect Slack context
Check your group folder name or workspace path:
- Folder starts with `slack_` (e.g., `slack_engineering`, `slack_general`)
- Or check `/workspace/group/` path for `slack_` prefix
## Formatting reference
### Text styles
| Style | Syntax | Example |
|-------|--------|---------|
| Bold | `*text*` | *bold text* |
| Italic | `_text_` | _italic text_ |
| Strikethrough | `~text~` | ~strikethrough~ |
| Code (inline) | `` `code` `` | `inline code` |
| Code block | ` ```code``` ` | Multi-line code |
### Links and mentions
```
<https://example.com|Link text> # Named link
<https://example.com> # Auto-linked URL
<@U1234567890> # Mention user by ID
<#C1234567890> # Mention channel by ID
<!here> # @here
<!channel> # @channel
```
### Lists
Slack supports simple bullet lists but NOT numbered lists:
```
• First item
• Second item
• Third item
```
Use `•` (bullet character) or `- ` or `* ` for bullets.
### Block quotes
```
> This is a block quote
> It can span multiple lines
```
### Emoji
Use standard emoji shortcodes: `:white_check_mark:`, `:x:`, `:rocket:`, `:tada:`
## What NOT to use
- **NO** `##` headings (use `*Bold text*` for headers instead)
- **NO** `**double asterisks**` for bold (use `*single asterisks*`)
- **NO** `[text](url)` links (use `<url|text>` instead)
- **NO** `1.` numbered lists (use bullets with numbers: `• 1. First`)
- **NO** tables (use code blocks or plain text alignment)
- **NO** `---` horizontal rules
## Example message
```
*Daily Standup Summary*
_March 21, 2026_
• *Completed:* Fixed authentication bug in login flow
• *In Progress:* Building new dashboard widgets
• *Blocked:* Waiting on API access from DevOps
> Next sync: Monday 10am
:white_check_mark: All tests passing | <https://ci.example.com/builds/123|View Build>
```
## Quick rules
1. Use `*bold*` not `**bold**`
2. Use `<url|text>` not `[text](url)`
3. Use `•` bullets, avoid numbered lists
4. Use `:emoji:` shortcodes
5. Quote blocks with `>`
6. Skip headings — use bold text instead
+5
View File
@@ -51,6 +51,7 @@ fi
need_install() {
[ ! -f src/channels/slack.ts ] && return 0
[ ! -f container/skills/slack-formatting/SKILL.md ] && return 0
! grep -q "^import './slack.js';" src/channels/index.ts 2>/dev/null && return 0
return 1
}
@@ -67,6 +68,10 @@ if need_install; then
log "Copying adapter from ${CHANNELS_BRANCH}"
git show "${CHANNELS_BRANCH}:src/channels/slack.ts" > src/channels/slack.ts
# Slack formatting container skill — reaches agents via ~/.claude/skills.
mkdir -p container/skills/slack-formatting
git show "${CHANNELS_BRANCH}:container/skills/slack-formatting/SKILL.md" > container/skills/slack-formatting/SKILL.md
# Append self-registration import if missing.
if ! grep -q "^import './slack.js';" src/channels/index.ts; then
echo "import './slack.js';" >> src/channels/index.ts
+3
View File
@@ -15,6 +15,7 @@ echo "=== NANOCLAW SETUP: INSTALL_SLACK ==="
needs_install=false
[[ -f src/channels/slack.ts ]] || needs_install=true
[[ -f container/skills/slack-formatting/SKILL.md ]] || needs_install=true
grep -q "import './slack.js';" src/channels/index.ts || needs_install=true
grep -q '"@chat-adapter/slack"' package.json || needs_install=true
[[ -d node_modules/@chat-adapter/slack ]] || needs_install=true
@@ -30,6 +31,8 @@ git fetch origin channels
echo "STEP: copy-files"
git show origin/channels:src/channels/slack.ts > src/channels/slack.ts
mkdir -p container/skills/slack-formatting
git show origin/channels:container/skills/slack-formatting/SKILL.md > container/skills/slack-formatting/SKILL.md
echo "STEP: register-import"
if ! grep -q "import './slack.js';" src/channels/index.ts; then