Atlas / MCP servers / mattlevine / Sideboard

SideboardBLOCK

mcp/mattlevine/sideboard
Verdict
BLOCK
Grade
F
Trust score
41 /100
Exposed tools
93 55r · 35w · 3d
Transport
stdio · streamable-http
License
Apache-2.0
Stars
2
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

Orchestrate a fleet of coding agents on your Mac. Isolated git worktrees. A kanban of the whole fleet. An orchestrator that can drive it. A phone app, CLI, and MCP so you can reach this machine — without a cloud workspace.

Peers often spawn one agent per git worktree. Sideboard isolates the checkout — one workspace per ticket, PR, or named branch — and runs as many agents as that workspace needs. Sibling chats share the files. The remaining job is an orchestration tier: an agent that can reason about those chats, a board where you can see that, and a phone app, CLI, and MCP so you can reach this machine — without moving the repo into someone else’s cloud.

Sideboard started as a local port when Conductor moved that tier into a paid cloud, then added the pieces that still belong on this Mac: MCP orchestration, a global kanban, a phone app, and CLI / MCP so other systems can drive it. Agents are plugs (Claude Code, Codex, OpenCode, Cursor). Compute stays on this machine (corporate VPN, private git, internal APIs). The phone app is remote control, not a rented sandbox.

  1. A global board for you — status, live output, and fan-out across every thread
  2. An MCP for the agents — list threads, wait on turns, read diffs, orchestrate the fleet, and present artifacts, schemas, and files in the desktop UI
  3. A phone app, CLI, and MCP to this Mac — pair the phone from Settings → Remote; register MCP from any harness; script the fleet without the GUI

attach / adopt remain the door back to the native harness — move in and out of Sideboard as you choose.

Run agents in isolated thread/* worktrees from the CLI, desktop, or MCP. The Mac must stay awake for the phone to reach it, and for scheduled jobs to fire — opt in from Settings → Advanced.

Agents and backends are plugs, not the product. CLI, MCP, and the des

Read from source at commit 92efd9436e15OBSERVED · 2026-10-12
Advertisement
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code
claude mcp add core --env ACTIONS_ID_TOKEN_REQUEST_TOKEN=${ACTIONS_ID_TOKEN_REQUEST_TOKEN} --env ACTIONS_ID_TOKEN_REQUEST_URL=${ACTIONS_ID_TOKEN_REQUEST_URL} --env APPLE_APP_SPECIFIC_PASSWORD=${APPLE_APP_SPECIFIC_PASSWORD} --env CLAUDE_CODE_OAUTH_TOKEN=${CLAUDE_CODE_OAUTH_TOKEN} -- npx -y @sideboard-ai/[email protected]
claude-desktop
{
  "mcpServers": {
    "core": {
      "command": "npx",
      "args": [
        "-y",
        "@sideboard-ai/[email protected]"
      ],
      "env": {
        "ACTIONS_ID_TOKEN_REQUEST_TOKEN": "${ACTIONS_ID_TOKEN_REQUEST_TOKEN}",
        "ACTIONS_ID_TOKEN_REQUEST_URL": "${ACTIONS_ID_TOKEN_REQUEST_URL}",
        "APPLE_APP_SPECIFIC_PASSWORD": "${APPLE_APP_SPECIFIC_PASSWORD}",
        "CLAUDE_CODE_OAUTH_TOKEN": "${CLAUDE_CODE_OAUTH_TOKEN}"
      }
    }
  }
}
03

Exposed tools (93)

55 read · 35 write · 3 destructive. Blast radius: 3 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.

ToolRiskDescription
Agentreadscan auth · 4 tools · 12s
CompactreadSummarized conversation
ReadreadRead auth.ts
SideboardreadSideboard desktop Brightsy MCP client
SkillreadUsing /long-running
TaskOutputreadWait for task_1
abletime_commentwriteAdd a markdown comment on an AbleTime task (id or CRM-232). When reviewing a PR or ticket, show the draft in chat and wait until they type a next step — do not ask_user after the review. The author sees this immediately.
abletime_create_taskwriteCreate an AbleTime task in a project. Call abletime_list_projects if you do not have a project id. Pass parent (CRM-232) for a spin-off. New tasks start in todo (or backlog).
abletime_download_attachmentreadDownload an AbleTime task file into
abletime_ensure_taskwriteFind or create an AbleTime task for this work, then create_workspace with sourceType=ticket.
abletime_get_taskread
abletime_list_projectswriteList AbleTime projects (and categories). Use a project id on create/ensure.
abletime_list_tasksreadList open AbleTime tasks (excludes done/archived). Optional projectId filter. Pass updatedSince for tasks updated since then and any comments on that page.
abletime_orientationreadCall first when using AbleTime. Returns viewer, active tasks, and projects.
abletime_search_tasksreadSearch AbleTime tasks by text, reference, or tag. Pass updatedSince for tasks updated since then and any comments on that page.
abletime_update_taskwriteUpdate an AbleTime task (id or CRM-232). Pass title, description, state, labels, project, parent, and/or relations. labels replaces tags. project is name or id (tasks stay in a project). parent is CRM-232 or
add_projectwriteRegister a git repo as a Sideboard workspace
add_stack_layerwriteAdd a branch on top of the current stack (
archive_chatreadArchive a thread (stops agent/dev, runs archive script, removes worktree when last chat tab). Coordinators commit, push, and open PRs by asking the worktree agent (ask_git). Merge only when the user explicitly asked.
ask_gitread
ask_userread
create_pr_stackwriteCreate a new GitHub PR stack with one Sideboard worktree per layer (bottom→top branch names). Requires
create_schedulewrite
create_workspacewrite
delete_envdestructiveDelete a Settings → Environment variable. scope=project uses the project prefix (same rule as set_env). Does not print the stored value.
delete_scheduledestructiveDelete a local schedule. Pass id from list_schedules.
fanoutwriteBest-of-n: create one thread per agent with the same prompt (parallel attempts)
fork_chatread
fork_workspaceread
get_chatread
get_diffreadCompact diff summary (capped hunks, paginated)
get_pr_checksreadSnapshot of GitHub PR checks for a worktree thread (
get_pr_stackreadLoad the GitHub PR stack for a thread worktree (
get_run_logwriteRead the Run-tab terminal for a worktree script (same stdout/stderr as the desktop Dev pane). Default is a tail — raise
get_turn_resultread
get_viewer_contextreadRead account and project user context (Settings → Agents / Projects): roles, tickets, and review queues as freeform text. Orchestration must pass repoPath from list_projects for project context. Worktree turns may omit repoPath (uses cwd).
github_commentwriteAdd a markdown comment on a GitHub issue (#123 or URL). Uses Account gh. When reviewing a PR or ticket, show the draft in chat and wait until they type a next step — do not ask_user after the review. The author sees this immediately.
github_create_issuewriteCreate a GitHub issue. Pass parent (#123) to mark a spin-off in the body.
github_download_attachmentreadDownload a GitHub issue file (github.com/user-attachments/... or githubusercontent.com) into
github_get_issuereadGet a GitHub issue (#123 or URL): body, comments, state, projects, attachments. Re-fetch to read new comments. projectsError means GitHub refused Projects (usually missing read:project — run
github_list_projectsreadList open GitHub Projects for the signed-in user and this repo owner (title, number, id). Pass a title as project on github_update_issue. If GitHub says the token is missing read:project, run
github_search_issuesreadSearch or list open GitHub issues in this repo via Account gh. Default 40; pass query and/or limit (max 250) when truncated. assignee: me, unassigned, all, or a login. Pass updatedSince for new/updated tickets and new comments (e.g. “any updates since yesterday?”).
github_update_issuewriteUpdate a GitHub issue (#123). Pass title, body, state (open|closed), labels, project, parent, and/or relations. labels replaces all names (pass [] to clear). project is a Project title, or
linear_commentwriteAdd a markdown comment on a Linear issue (uuid or ENG-123). When reviewing a PR or ticket, show the draft in chat and wait until they type a next step — do not ask_user after the review. The author sees this immediately.
linear_create_issuewriteCreate a Linear issue. Call linear_list_teams first. team is id/key/name; state is name/type/id; assignee is
linear_download_attachmentreadDownload a Linear file attachment into
linear_get_issueread
linear_list_projectsreadList Linear projects (id, name, slugId). Pass a name or id as project on linear_update_issue. linear_get_issue and search rows also include the project a ticket is on.
linear_list_teamsreadList Linear teams (id, key, name), workflow states, and the active cycle. Use team key on create; state name or type on create/update; cycle name/
linear_search_issuesreadSearch or list open Linear issues. Default 40; pass query and/or limit (max 250) when truncated. assignee: me, unassigned, all (default with query), or a user id/name. Pass updatedSince for new/updated tickets and new comments (e.g. “any updates since yesterday?”).
linear_update_issuewriteUpdate a Linear issue (uuid or ENG-123). Pass title, description, state, assignee, priority, cycle, labels, project, parent, and/or relations. Cycle/project/parent: name or id, or
list_boardread
list_branchesreadList git branches in a registered workspace. Pass repoPath from list_projects (unmerged into the default branch by default — for create_workspace sourceType=branch).
list_chatsread
list_envreadList Settings → Environment variable names (not values). scope=project keys use the project prefix (project name, uppercased, plus _). scope=account keys are shared by every project. Pass repoPath from list_projects when calling from orchestration so the reply includes this project prefix.
list_issuesread
list_modelsreadList models for an agent. Prefer Auto: do not call this unless you have a reason to pin a specific model (user request, cost/latency, capability). Omit agent to list all.
list_projectsread
list_prsreadList GitHub PRs for a registered workspace (the review surface for assigned ticket work — not the tickets). Pass repoPath from list_projects.
list_run_scriptswrite
list_scheduleswriteList local Sideboard schedules that trigger a chat when due. Jobs fire only while Sideboard.app is running on this Mac (sleep skips until wake).
list_teamsreadList Slack workspaces connected in Settings → Remote. Each row is team_id + name. Pass team_id to slack_list_channels, slack_list_users, slack_read, slack_post, and slack_replies.
notify_orchestratorread
open_pr_stack_layersreadMaterialize one worktree+thread per stack layer (or a single 1-based layer). Pass a thread ref already on the stack.
posthog_apiread
present_artifactread
present_filesread
present_planreadDraft the rollout
present_schemaread
remove_projectdestructiveUnregister a Sideboard workspace and archive its chats
request_reviewread
restore_chatreadRestore an archived thread (recreates worktree from branch when needed)
run_dev_scriptwrite
run_schedulewriteFire a schedule now (does not wait for nextRunAt). Queues the prompt on the target chat or starts a new Global chat. If Sideboard.app is running, the desktop drains the turn.
run_setupwriteRe-run workspace setup (Sideboard/Conductor settings, .cursor/worktrees.json, or script/setup). New worktrees already run this automatically.
send_to_chatwriteSteer a prompt on a workspace chat (Settings → Follow-up, default steer: interrupt the in-flight turn and start now, same as the workspace composer). Use after create_workspace to start or continue a conversation. For commit/push/PR, prefer ask_git (canonical desktop-button phrases). Send
set_caffeinatewrite
set_envwrite
set_workspace_tagswrite
slack_list_channelsreadList channels in a connected Slack workspace. Pass team_id from list_teams.
slack_list_usersreadList or search people in a connected Slack workspace (for DMs / @mentions). Pass team_id from list_teams. Optional query matches name, display name, real name, or email.
slack_postwrite
slack_readwriteRead recent messages in a Slack channel or DM, or a thread when ts is set. Pass team_id from list_teams and #channel, @user, or a C.../D.../U... id.
slack_repliesread
start_board_cardwrite
stop_chatwrite
stop_dev_scriptwriteStop a run script started with run_dev_script or the desktop Dev button (same as UI Stop). Omit name to stop all scripts on this worktree. Worktree turns may omit ref (uses cwd).
stop_jobwrite
toolreadtool
update_schedulewriteUpdate a local schedule (prompt, cadence, target chat, enabled). Pass id from list_schedules.
update_viewer_contextwriteReplace account or project user context (Settings → Agents / Projects). Never call until the user confirmed. Show the proposed text, ask_user (Save this context / Do not save), wait, then pass confirmed=true. Empty context clears that field.
wait_for_jobread
wait_for_turnread
04

Trust audit

BLOCKgrade F · trust 41/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryFAIL
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)FAIL
L3Class-specific surfaceWARN
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (12 observation(s))
Network
declared (11 observation(s))
Shell
declared (6 observation(s))
Dependencies
not all pinned
Secrets in source
found

Findings (25)

HIGHInventory / provenance · inv.suspicious_name · CWE-1104
packages/core/src/mcp/issue-payload.ts
issue-payload.ts
Why it matters. member named after an attack tool
Fix. remove or justify
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
apps/desktop/src/renderer/src/lib/artifacts.ts:689
var run = new Function('module', 'exports', 'require', 'React', 'ReactDOM', transformed);
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHPrompt injection · prompt.hide_from_user · CWE-94, CWE-1427
.claude/skills/long-running/SKILL.md:84
Never tell the user “say status when it’s done.” You wait — unless you decided to stop.
Why it matters. asks the agent to act without the user's knowledge
HIGHPrompt injection · prompt.zero_width · CWE-94, CWE-1427
.context/cli/desktop-job-tail.txt:1
<?xml version="1.0" encoding="utf-8"?><Error><Code>BlobNotFound</Code><Message>The specified blob does not exist.
Why it matters. invisible characters in instruction text
Fix. strip non-printing characters
MEDIUMInventory / provenance · inv.binary · CWE-1104
apps/desktop/build/icon.icns
icon.icns
Why it matters. a compiled or binary member cannot be reviewed from source
Fix. ship source, or explain the binary in the README
MEDIUMInventory / provenance · inv.symlink · CWE-1104
.cursor/skills/agent-rpc
.cursor/skills/agent-rpc
Why it matters. link not followed
MEDIUMInventory / provenance · inv.symlink · CWE-1104
.cursor/skills/bugbot-follow-ups
.cursor/skills/bugbot-follow-ups
Why it matters. link not followed
MEDIUMInventory / provenance · inv.symlink · CWE-1104
.cursor/skills/glossary
.cursor/skills/glossary
Why it matters. link not followed
MEDIUMInventory / provenance · inv.symlink · CWE-1104
.cursor/skills/graph-engineering
.cursor/skills/graph-engineering
Why it matters. link not followed
MEDIUMInventory / provenance · inv.symlink · CWE-1104
.cursor/skills/long-running/SKILL.md
.cursor/skills/long-running/SKILL.md
Why it matters. link not followed
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
apps/mobile/start-dev.sh:56
curl -fsS -o /dev/null --max-time 1 "http://127.0.0.1:${port}"
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
packages/core/src/integrations/abletime.test.ts:255
token: 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1In0.sig',
MEDIUMHard-coded secrets · secret.slack · CWE-798, CWE-321
packages/core/src/slack/relay-hub.test.ts:87
'xoxp-alice-user',
MEDIUMFilesystem / path · mcp.destructive_tools · CWE-22, CWE-59
delete_env, delete_schedule, remove_project
Why it matters. 3 tool(s) can delete or overwrite
Fix. prefer a read-only mode or scoped tokens; the page states the blast radius
LOWInventory / provenance · inv.suspicious_name · CWE-1104
packages/core/src/mcp/issue-payload.test.ts
issue-payload.test.ts
Why it matters. member named after an attack tool
Fix. remove or justify
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
packages/core/src/store/run-log.ts:76
const hash = createHash('sha1').update(norm).digest('hex').slice(0, 16);
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
packages/core/src/store/setup-log.ts:84
return `wt-${createHash('sha1').update(norm).digest('hex').slice(0, 16)}`;
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
.claude/skills/bugbot-follow-ups/collect.sh:7
ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
apps/desktop/electron.vite.config.ts:41
'../../packages/core/src/agents/message-parts.ts',
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
apps/desktop/electron.vite.config.ts:45
'../../packages/core/src/agents/usage.ts',
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
apps/desktop/electron.vite.config.ts:49
'../../packages/core/src/agents/claude-usage.ts',
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
apps/desktop/electron.vite.config.ts:53
'../../packages/core/src/store/usage-on-limit.ts',
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
README.md:349
AbleTime requires an HTTPS redirect, so the browser returns to `https://www.sideboard.cloud/oauth/abletime/callback` (same host as the CIMD). That page opens the desktop listener at `http://127.0.0.1:
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
README.md:358
Callback URL for the Sideboard Linear OAuth app: `http://127.0.0.1:19848/callback`. Override the client with `SIDEBOARD_LINEAR_CLIENT_ID` (secret optional — the desktop uses PKCE). You will not see th
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
apps/desktop/src/renderer/src/lib/preview-url.test.ts:12
expect(normalizePreviewUrl('127.0.0.1:8080/app')).toBe('http://127.0.0.1:8080/app');

Gates applied: instruction_override, no_behavioural_pass.

Audited 2026-10-12 · audit v0.4.1 · source sha 92efd9436e15full audit observations/trust-audit/mcp-server/mattlevine__sideboard.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-1292efd9436e15BLOCKF41first audit
06

Questions

What tools does @sideboard-ai/cli expose?

93 in total: 55 read-only, 35 that write, and 3 that can delete or overwrite (delete_env, delete_schedule, remove_project). Every one is listed on this page with its risk.

Is @sideboard-ai/cli safe to connect to an agent?

No — not without reading the findings first. The audit graded it F (41/100) and found 4 critical or high issues in the source. Each one is listed on this page with the file and line it is on. Separately from the audit: 3 of its tools can destroy data, so scope the token you give it to what you actually need.

What credentials does @sideboard-ai/cli need?

It reads ACTIONS_ID_TOKEN_REQUEST_TOKEN, ACTIONS_ID_TOKEN_REQUEST_URL, APPLE_APP_SPECIFIC_PASSWORD, CLAUDE_CODE_OAUTH_TOKEN, CURSOR_API_KEY, GH_TOKEN, GIT_ASKPASS, NODE_AUTH_TOKEN, NPM_TOKEN, SIDEBOARD_ABLETIME_OAUTH_CLIENT_ID, SIDEBOARD_ABLETIME_OAUTH_REDIRECT and SIDEBOARD_GIT_AUTH_DIR from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does @sideboard-ai/cli run?

It speaks stdio and streamable-http, so it runs as a local process your client starts. It is published on npm as @sideboard-ai/core at 0.1.293.

How current is this page?

The grade is for one exact copy of the source (92efd9436e15), read on 2026-10-12. The repository is watched and re-audited when it changes.

Advertisement