add-mattermost
Add a self-hosted or cloud Mattermost bot channel through the Chat SDK bridge, reusing a local server when available and offering an evaluation server when none exists.
git clone --depth 1 https://github.com/nanocoai/nanoclaw /tmp/add-mattermost && cp -r /tmp/add-mattermost/.claude/skills/add-mattermost ~/.claude/skills/add-mattermostSKILL.md
# Add Mattermost Channel
Adds Mattermost DMs, channels, threads, files, reactions, and interactive
approval cards. Messages arrive over Mattermost's WebSocket; card clicks return
to NanoClaw over an authenticated HTTP callback. Every step is safe to re-run.
## Discover the server first
Do this before installing the adapter or asking for a URL. The goal is to
reuse a healthy Mattermost the user already has and establish one canonical
base URL.
1. Check an existing `MATTERMOST_BASE_URL` in the current environment and
NanoClaw env/config files. Do not print tokens or dump whole env files.
2. Probe likely local URLs, at least `http://localhost:8065` and
`http://127.0.0.1:8065`, using `GET /api/v4/system/ping`. A listening port
alone is not evidence that the service is Mattermost.
3. Inspect Docker/Compose for Mattermost containers. If a matching container
exists but is stopped, offer to start it; do not start or recreate it
without the user's approval.
4. If you find a healthy server, show its URL. Ask the user to use this server,
enter a different URL, or create the local evaluation server. Do not select a
server automatically. Treat the localhost and 127.0.0.1 endpoints for the
same container as one server.
5. If nothing local is found, ask whether the user has a remote Mattermost.
If not, offer the local evaluation installation in
[LOCAL_SERVER.md](LOCAL_SERVER.md). Read that file only for local server
discovery, repair, or installation.
Set `MATTERMOST_BASE_URL` to the chosen canonical URL (scheme included, no
trailing slash), then use that exact hostname in browser/Desktop setup. Do not
silently install Mattermost: it runs containers, binds a port, and persists
data, so show what will be created and get approval first.
## Apply
### 1. Detect the server
Test the configured URL and the standard local URLs. A detected server is only
a suggestion. The user must select the server.
```nc:run capture:discovery=.discovery,detected_url=.base_url,detected_config_access=.config_access,detected_container=.mattermost_container effect:fetch
node .claude/skills/add-mattermost/scripts/discover-server.mjs
```
```nc:operator when:discovery=found
NanoClaw found a healthy Mattermost server at {{detected_url}}. You can use this server, enter a different URL, or create a local evaluation server.
```
```nc:prompt server_choice when:discovery=found normalize:lower validate:^(use|enter|create)$
Enter `use` to use {{detected_url}}. Enter `enter` to specify a different Mattermost URL. Enter `create` to create a local evaluation server.
```
```nc:run capture:base_url=.base_url,config_access=.config_access,mattermost_container=.mattermost_container effect:fetch when:server_choice=use
node .claude/skills/add-mattermost/scripts/select-server.mjs use "{{detected_url}}" "{{detected_config_access}}" "{{detected_container}}"
```
```nc:prompt entered_url when:server_choice=enter normalize:rstrip-slash validate:^https?://(?:[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?|\[[0-9A-Fa-f:.]+\])(?::[0-9]{1,5})?(?:/[A-Za-z0-9._~%+-]+)*$
Enter the Mattermost base URL. Include the scheme, for example `https://mattermost.example.com`.
```
```nc:run capture:base_url=.base_url,config_access=.config_access,mattermost_container=.mattermost_container effect:fetch when:server_choice=enter
node .claude/skills/add-mattermost/scripts/select-server.mjs enter "{{entered_url}}"
```
```nc:run capture:create_requested when:server_choice=create
printf 'yes\n'
```
```nc:operator when:discovery=none
NanoClaw did not find a healthy Mattermost server. You can enter a server URL or create a local evaluation server.
```
```nc:prompt no_server_choice when:discovery=none normalize:lower validate:^(enter|create)$
Enter `enter` to specify a Mattermost URL. Enter `create` to create a local evaluation server.
```
```nc:prompt entered_url_new when:no_server_choice=enter normalize:rstrip-slash validate:^https?://(?:[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?|\[[0-9A-Fa-f:.]+\])(?::[0-9]{1,5})?(?:/[A-Za-z0-9._~%+-]+)*$
Enter the Mattermost base URL. Include the scheme, for example `https://mattermost.example.com`.
```
```nc:run capture:base_url=.base_url,config_access=.config_access,mattermost_container=.mattermost_container effect:fetch when:no_server_choice=enter
node .claude/skills/add-mattermost/scripts/select-server.mjs enter "{{entered_url_new}}"
```
```nc:run capture:create_requested when:no_server_choice=create
printf 'yes\n'
```
Explain what the installation creates. Give the user time to review the details. Then get approval.
```nc:operator when:create_requested=yes
The local evaluation server runs Mattermost Team Edition and PostgreSQL in containers. The installation creates a Docker network and named volumes. It saves configuration files in .nanoclaw/mattermost. It binds the server to 127.0.0.1:8065. You need Docker and Docker Compose. Port 8065 must be free. If the port is in use, the installation stops and makes no changes.
```
```nc:prompt local_install_approval when:create_requested=yes normalize:lower validate:^install$
Enter `install` to create and start these local resources.
```
After approval, verify the requirements and create the stack. Wait for a
maximum of 60 seconds for Mattermost. If the operation fails, show the last
100 service log lines and stop.
```nc:run effect:external when:local_install_approval=install
docker info >/dev/null && docker compose version >/dev/null
node -e 'const net=require("node:net");const s=net.createServer();s.once("error",()=>process.exit(1));s.listen(8065,"127.0.0.1",()=>s.close())'
mkdir -p .nanoclaw/mattermost
cp .claude/skills/add-mattermost/assets/compose.yml .nanoclaw/mattermost/compose.yml
test -f .nanoclaw/mattermost/.env || { umask 077; printf 'MATTERMOST_DB_PASSWORD=%s\n' "$(openssl rand -hex 24)" > .nanoclaw/mattermost/.env; }
docker compose -f .nanoclaw/mattermost/compose.yml up -d
for attempt in $(seq 1 30); do curl -fsS --connect-timeout 1 --maAdd local office-document-to-Markdown conversion to NanoClaw agent containers with the pinned Firecrawl AnyDoc CLI. Use when agents need to read attached Word, PowerPoint, Excel, OpenDocument, RTF, EPUB, CSV, or text-based PDF files without uploading them to a hosted parser.
Add Atomic Chat MCP server so the container agent can call local models served by the Atomic Chat desktop app via its OpenAI-compatible API.
Add clidash — a zero-dependency, read-only web dashboard that derives its tabs and tables at runtime from any CLI that lists resources as JSON. Ships pre-wired for NanoClaw's ncl CLI (agent groups, sessions, channels, users, roles), plus message-activity charts, a log tail, and a read-only file viewer for group skills/CLAUDE.md/profiles.
Use Codex (OpenAI's codex app-server) as a full agent provider — planning, tool orchestration, MCP tools, server-side history, session resume — alongside or instead of Claude. ChatGPT subscription or OpenAI API key, vault-only via OneCLI. Per-group via `ncl groups config update --provider codex`. Distinct from using OpenAI as an MCP tool (where Claude remains the planner).
Add a monitoring dashboard to NanoClaw. Installs @nanoco/nanoclaw-dashboard and a pusher that sends periodic JSON snapshots.
Add DeltaChat channel integration via @deltachat/stdio-rpc-server. Native adapter — no Chat SDK bridge. Email-based messaging with end-to-end encryption.
Add Dial channel integration — a real phone number for SMS and AI voice calls via the Dial platform (getdial.ai). Native adapter — no Chat SDK bridge.
Add another phone number to an existing Dial channel — a second (or third) public line for the agent, so one NanoClaw install answers SMS and AI voice calls on multiple numbers. Use when Dial is already installed and the operator wants an additional number (e.g. a personal line plus a support line). Requires the Dial channel to already be installed (see /add-dial).