GitHub - mobydeck/skate: Access Mattermost Boards tasks from CLI and AI agents via MCP
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.
Install
Homebrew (macOS / Linux)
brew install mobydeck/tap/skate
macOS note: If Gatekeeper blocks the binary on first run, allow it with:
xattr -d com.apple.quarantine $(which skate)
Binary download
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/Setup
1. Initialize global config
You'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.
2. Initialize per-project config
In your project directory:
This 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.
3. Connect an AI agent
skate setup claude-code # Claude Code skate setup cursor # Cursor skate setup codex # Codex skate setup opencode # OpenCode skate setup roocode # RooCode
This 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.
4. Bootstrap an AI agent session
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
CLI Commands
Boards
$ 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 output
Tasks
By 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 tasks
Task 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
Task Management
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 attachment
Time Tracking
Time 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 entry
Configuration
skate 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 substring
Workflow guide (SKILL.md)
skate 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 current
skate 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.
Cache
skate cache ls # List cached download files (size + mtime) skate cache clean # Delete all cached download files
The 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).
Output Formats
All data commands support --json / -j and --yaml / -y flags:
skate boards --json skate tasks --yaml skate task <ID> -j skate task-files <ID> -y
Pretty markdown rendering (--pretty / -P)
For 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 -R
This 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.
MCP Tools
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 |
Example Prompts for AI Agents
"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"
Translation
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.
Config Files
- 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: llama3
Environment Variables
All 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 |
Building
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 binaries
Version is set at build time via ldflags. It defaults to dev, or auto-derives from git tags:
VERSION=1.0.0 make build # explicit versionArchitecture
- 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
License
See LICENSE for details.