Access Mattermost Boards tasks from CLI and AI agents via MCP.
Skate lets you manage project tasks, track time, and collaborate with AI coding agents — all from your terminal. It's a thin, stateless Go client over the Mattermost Boards API with zero runtime dependencies.
brew install mobydeck/tap/skatemacOS note: If Gatekeeper blocks the binary on first run, allow it with:
xattr -d com.apple.quarantine $(which skate)
Download from Releases, or build from source:
git clone https://github.com/mobydeck/skate
cd skate
make install # builds and installs to ~/.local/bin/Cross-build for all platforms:
just cross-build # outputs to dist/skate initYou'll need:
- Your Mattermost server URL (e.g.,
https://mm.example.com) - A personal access token
- Your team ID (auto-detected if only one team)
Re-run skate init anytime to update settings — existing values are shown as defaults.
In your project directory:
skate local-initThis creates .skate.yaml with the board ID for this project. Skate walks up directories to find the nearest .skate.yaml and merges it with the global config, so nested folders inherit settings. Re-run to change the board.
skate setup claude-code # Claude Code
skate setup cursor # Cursor
skate setup codex # Codex
skate setup opencode # OpenCode
skate setup roocode # RooCodeThis registers the MCP server and installs a skill file (SKILL.md — the workflow guide) that teaches the agent how to use Skate.
Use --project / -p flag to install for the current project only (writes to .mcp.json instead of global config).
Re-run after every skate upgrade — skate setup overwrites the installed SKILL.md with the version embedded in the new binary, so the agent picks up new tools and conventions. Use diff <(skate skill) <(tail -n +6 ~/.claude/skills/skate/SKILL.md) to check whether the installed copy is in sync.
In most cases nothing extra is needed:
- The MCP server returns the workflow guide's location during the
initializehandshake (theinstructionsfield). Claude Code and other compliant clients inject this into the model's context automatically — no manual prompt required. - If no installed
SKILL.mdis found (e.g.--projectinstall or unknown agent), the handshake instead tells the agent to call theskate_helpMCP tool, which returns the same content inline.
If an agent doesn't honor either signal, paste the output of skate prompt into the chat:
skate prompt claude-code # or: cursor, codexBefore starting work, read and follow rules in /home/user/.claude/skills/skate/SKILL.md
$ skate boards
ID TITLE TYPE
bto6yyshu77yj5x5mbu34cnhzcr 🗓️ Sprint Planner Private
bht3p6dq1i381jrzx8kngmt4gjw 🎯 Arthur – Tasks Private
bqn9n36errtymuqk1ph7xy7coiw 📖 Read Books Private
skate boards # List all boards
skate boards --json # JSON output
skate boards --yaml # YAML outputBy default, skate tasks shows only Not Started and In Progress tasks, sorted by priority (high to low).
$ skate tasks
ID TITLE STATUS PRIORITY ASSIGNEE
c4cf6f4wzbjgxdm3hpa7iygtjdo Task translation middleware Not Started 2. Medium
cuppcm819atnixx71qg9i485jsr listing tasks In Progress 1. High 🔥
skate tasks # Active tasks from .skate.yaml board
skate tasks --all # All tasks regardless of status
skate tasks --status "Not Started" # Filter by specific status
skate tasks --board <BOARD_ID> # Specific board
skate tasks --mine # Only tasks assigned to you
skate tasks --all-users # All users (overrides only_mine config)
skate tasks --json # JSON output
skate task <TASK_ID> # View task details (last 5 comments)
skate task <TASK_ID> --full # View task with all comments
skate task <TASK_ID> -T # View task without translation
skate task <TASK_ID> --json # Full task data as JSON
skate comments <TASK_ID> # View all comments for a task
skate task-files <TASK_ID> # List attached files
skate download <FILE_ID> # Download a file (board from .skate.yaml)
skate download <FILE_ID> -b <BOARD> # Download from specific board
skate find "search term" # Search tasks by title and content
skate find "bug" --json # Search with JSON output
skate next # Top-priority Not Started task (renders full task)
skate next --mine # Top of queue limited to your assignments
skate state # Snapshot: who you are, running timer, your in-progress tasksTask detail renders as markdown:
$ skate task c4cf6f4wzbjgxdm3hpa7iygtjdo
# 📪 Task translation middleware
| Property | Value |
|----------|-------|
| Status | In Progress |
| Priority | 2. Medium |
## Description
Add translation middleware for non-English board content...
## Comments
**@arthur** (Apr 3, 2026):
> Implemented translation middleware with OpenAI SDK
## Time Tracking
- @arthur: 00:08
Total: 00:08
skate create "Fix login bug" --status "Not Started" --priority "High"
skate create "New feature" --description "Detailed description here"
skate create "Triage failing job" --assignee arthur # accepts username or user ID
skate statuses # list available statuses for the board
skate update <TASK_ID> --title "New title" # rename a task
skate update <TASK_ID> --priority "High" # change priority
skate update <TASK_ID> --assignee arthur # reassign (username or user ID)
skate update <TASK_ID> --status "In Progress" -t # status + start timer
skate update-status <TASK_ID> "In Progress" # shortcut for --status
skate update-status <TASK_ID> "In Progress" -t # update status + start timer
skate update-status <ID1> <ID2> <ID3> "Completed" # batch close (continues on failures)
skate comment <TASK_ID> "Implemented the fix, running tests"
skate add-content <TASK_ID> "Discovery: the API requires ..." # text block (default)
skate add-content <TASK_ID> "Architecture" -t h2 # heading block
skate add-content <TASK_ID> -t divider # divider block
skate add-content <TASK_ID> "Review audit" -t checkbox # checkbox block
skate add-content <TASK_ID> ./diagram.png -t image # inline image block
skate attach <TASK_ID> ./screenshot.png
skate edit-block <TASK_ID> <BLOCK_ID> "new text" # rewrite a comment, content block, or heading
skate delete-block <TASK_ID> <BLOCK_ID> # remove a wrong comment, content block, or attachmentTime tracking requires the Mattermost Boards time tracking plugin. If unavailable, timer commands will print a message and continue without error.
$ skate timer-start c4cf6f4wzbjgxdm3hpa7iygtjdo
Timer started on: Task translation middleware
$ skate timer-stop --notes "Completed implementation"
Timer stopped: Task translation middleware — 00:08
skate timer-start <TASK_ID> # Start timer (auto-stops previous)
skate timer-stop --notes "Completed feature" # Stop running timer
skate time-add <TASK_ID> 01:30 --notes "Code review" # Add manual time
skate time-add <TASK_ID> 02:00 --date 2026-04-01 # Backdate entryskate config # Show effective config (merged global + local + env)
skate config --json # JSON output
skate me # Show the authenticated Mattermost user
skate users # List team members
skate users arthur # Filter team members by username/name substringskate skill # Print the embedded workflow guide
skate skill | less # Paginate
diff <(skate skill) <(tail -n +6 ~/.claude/skills/skate/SKILL.md) # Check installed copy is currentskate skill prints the same content the skate_help MCP tool returns. Useful for iterating on the guide and verifying that skate setup installed the latest version.
skate cache ls # List cached download files (size + mtime)
skate cache clean # Delete all cached download filesThe cache holds files saved by the skate_download MCP tool when an agent didn't pass an explicit output_path. Default location: ~/.cache/skate/downloads/ (Linux) / %LocalAppData%\skate\downloads\ (Windows).
All data commands support --json / -j and --yaml / -y flags:
skate boards --json
skate tasks --yaml
skate task <ID> -j
skate task-files <ID> -yFor commands that emit markdown (skate task, skate next, skate skill, skate comments), pass --pretty (or -P) to render via Glamour with terminal styling:
skate task <ID> -P
skate next --pretty
skate skill -P | less -RThis is a human-only ergonomics flag — it's intentionally hidden from --help and not advertised to AI agents. The rendered output contains ANSI escapes and is unsuitable for parsing or automation; use the default raw-markdown output (or --json) when scripting.
When stdout is not a TTY (e.g. piped to a file), Glamour falls back to plain reformatted text so pipelines don't get poisoned with escape codes.
When connected via MCP, AI agents can use these tools.
The MCP server's initialize response sets the instructions field to a one-line directive pointing the agent at the installed SKILL.md (or telling it to call skate_help if no file is installed). Most clients inject this into the model's context automatically, so the agent learns the workflow without any manual setup.
| Tool | Description |
|---|---|
skate_help |
Return the canonical Skate workflow guide (the same content as the installed SKILL.md) plus the server's configured board_id |
skate_statuses |
List available statuses for the board |
skate_boards |
List available boards |
skate_tasks |
List tasks (default: active only; show_all, mine, all_users flags) |
skate_next |
Pick the highest-priority Not Started task and return its full details |
skate_state |
Session-resume snapshot: user, running timer, your In Progress tasks |
skate_task |
Get task details as markdown (all comments shown via MCP; no_translate to skip translation) |
skate_update_status |
Change one or many task statuses (task_id single or task_ids array; optional start_timer for single) |
skate_update_task |
Update any of: title, icon, status, priority, assignee (optional start_timer) |
skate_create_task |
Create a new task (assignee accepts a user ID) |
skate_comment |
Add a comment to a task |
skate_add_content |
Add a content block (text, h1-h3, divider, checkbox, image) |
skate_attach |
Upload a local file and attach it to a task |
skate_edit_block |
Rewrite a content block, comment, or heading in place |
skate_delete_block |
Delete a content block, comment, or attachment by block ID |
skate_download |
Download an attached file. ≤32 KiB UTF-8 → inline; otherwise auto-saved to ~/.cache/skate/downloads/<file_id> (or output_path if given). |
skate_comments |
Get all comments for a task (no_translate to skip translation) |
skate_task_files |
List files attached to a task |
skate_find |
Search tasks by title and content |
skate_config |
Show effective configuration (mentions, translate) |
skate_me |
Show the authenticated Mattermost user (id, username) |
skate_users |
List team members (optional query substring filter) |
skate_timer_start |
Start timer on a task |
skate_timer_stop |
Stop running timer with notes |
skate_time_add |
Add manual time entry |
"Look at the board tasks, pick the highest priority unstarted task, and implement it"
"Check my current tasks and update the one I'm working on"
"Create a task for the bug I just found in the auth module"
"Start a timer, implement the task, then stop the timer with notes"
"List all tasks assigned to me that are In Progress"
"Take the next task by priority"
"Work on next task"
Skate can automatically translate non-English board content to English using any OpenAI-compatible API (OpenAI, Ollama, OpenRouter, etc.).
Enable in config:
# ~/.config/skate.yaml
translate:
enabled: true
provider: openai # or ollama, openrouter
model: gpt-5-mini # any chat model
base_url: "" # custom endpoint (e.g., http://localhost:11434/v1 for Ollama)
api_key: "sk-..." # API key (not needed for Ollama)Translation uses a fast heuristic to detect non-English text and only calls the API when needed. English content passes through untouched.
- Global:
~/.config/skate.yaml(Linux),%AppData%\skate\skate.yaml(Windows) - Local:
.skate.yaml(per project, walks up directories) - User cache:
~/.cache/skate/users.yaml(Linux),%LocalAppData%\skate\users.yaml(Windows)
# ~/.config/skate.yaml
mattermost_url: "https://mm.example.com"
token: "your-personal-access-token"
team_id: "your-team-id"
only_mine: false # show only your tasks by default
mentions: true # @mention users in agent comments (default: true)
translate:
enabled: false
provider: openai
model: gpt-5-mini
base_url: ""
api_key: ""# .skate.yaml (in project root)
board_id: "your-board-id"
# Local config can also override global settings per project:
# mattermost_url: "https://other-server.com"
# mentions: false
# translate:
# enabled: true
# model: llama3All config values can be overridden with environment variables:
| Variable | Description |
|---|---|
SKATE_URL |
Mattermost server URL |
SKATE_TOKEN |
Personal access token |
SKATE_TEAM_ID |
Team ID |
SKATE_BOARD_ID |
Default board ID |
SKATE_TRANSLATE_ENABLED |
Enable translation (true/1) |
SKATE_TRANSLATE_PROVIDER |
Translation provider |
SKATE_TRANSLATE_MODEL |
Model name |
SKATE_TRANSLATE_BASE_URL |
Custom API endpoint |
SKATE_TRANSLATE_API_KEY |
API key |
make build # build for current platform
make install # build + install to ~/.local/bin/
make test # run tests
just cross-build # cross-build for linux/darwin/windows (amd64 + arm64)
just release # create draft GitHub release with all binariesVersion is set at build time via ldflags. It defaults to dev, or auto-derives from git tags:
VERSION=1.0.0 make build # explicit version- Pure Go — single static binary, no runtime dependencies, cross-compilable to 5 platforms
- Stateless — no local database, all data lives in Mattermost
- User cache — resolved usernames cached in
~/.cache/skate/users.yaml(Linux) or%LocalAppData%\skate\(Windows) - MCP stdio — agents start skate on demand, zero idle cost
- Config merging — global config + local
.skate.yaml+ env vars (env wins) - Version — set via ldflags, shared across CLI, HTTP client User-Agent, and MCP server
See LICENSE for details.