| name | build-task-manager |
| description | Set up the task manager for this repo end-to-end: pick a manager (Linear / Jira / GitHub Issues / Notion / None), pick an integration method (MCP / CLI / plugin / API), verify the chosen integration is installed (offering to help install, wait for the user, or skip), ask the user how to fetch their tasks and try it (suggesting likely configuration issues on failure), then write `.claude/skills/claude-slack-bridge_list-tasks/SKILL.md` and verify it runs end-to-end. Returns a status of `configured` (with task_manager_label, task_manager_slug, integration_method) or `skipped`. Use as the task-manager phase of /process-setup. |
build-task-manager — set up the task manager and write the claude-slack-bridge_list-tasks helper
You run locally inside Claude Code (not via the Slack daemon). All clarifications go through AskUserQuestion. Do not call mcp__claude-slack-bridge__ask_on_slack from this skill.
This skill is the entire task-manager phase of /process-setup. By the time it returns, either:
- The user picked a manager, the integration is verified, the smoke-test succeeded, and
.claude/skills/claude-slack-bridge_list-tasks/SKILL.md has been generated (status: configured); or
- The user skipped (or aborted the install flow after retries), no helper skill was written (status:
skipped).
Return values the caller needs (printed as a fenced JSON block at the end of the final reply):
status — configured or skipped.
task_manager_label, task_manager_slug, integration_method — populated when status == "configured"; omitted otherwise.
Do not skip ahead to writing the helper skill until Step 3 has actually fetched tasks successfully.
Step 1 — pick a task manager
Ask via AskUserQuestion:
Which task manager do you use for this repo?
Options: Linear, Jira, GitHub Issues, Notion, None / skip.
If the answer is None / skip, return immediately with status: "skipped".
Record:
task_manager_label — the human label (e.g. Linear, GitHub Issues).
task_manager_slug — lowercase slug (linear, jira, github, notion).
Step 2 — pick the integration method and verify it's installed
2a. Integration method
Ask via AskUserQuestion:
How is {task_manager_label} integrated in this environment?
All four integration methods are valid for every manager — including GitHub. Do not assume gh for github; the user may prefer the GitHub MCP server, a custom plugin, or direct REST.
Options (single-select, in this order):
- MCP server — there is an MCP server providing task tools (e.g.
mcp__linear__list_issues, mcp__github__list_issues).
- CLI tool — there is a CLI installed (e.g.
gh, linear-cli, jira-cli).
- Plugin / slash command — there is a Claude plugin or slash command that lists tasks.
- Direct API (curl) — call the manager's HTTP API directly with credentials from env vars.
Record the choice as integration_method ∈ {mcp, cli, plugin, api}.
2b. Availability check (and offer to install)
Run the matching availability check based on integration_method. The point is to catch the "user picked Linear MCP but never installed the Linear MCP server" case early, so we can offer to help.
- mcp — read
cwd/.mcp.json and look for a server entry whose key plausibly matches {task_manager_slug} (e.g. linear, jira, github, notion). If none match, treat as not installed.
- cli — ask the user which CLI binary they intend to use (one short
AskUserQuestion, free-text — e.g. gh, linear, jira). Then run command -v <cli> via Bash (or where <cli> on Windows). Non-zero exit ⇒ not installed.
- plugin — ask the user which plugin / slash command they intend to use, then check whether it appears in the available skills/commands list for this session. Absent ⇒ not installed.
- api — skip the install check; API integration only needs env vars, which Step 3 will surface.
If the check says installed (or integration_method is api), continue to Step 3.
If the check says not installed, ask via AskUserQuestion:
{task_manager_label} ({integration_method}) doesn't appear to be installed in this repo. Want me to help you set it up?
Options:
- Yes, help me install it — proceed with the install flow below.
- I'll install it myself, wait for me — pause; ask the user to reply when they're done, then re-run 2b.
- Skip task manager integration — return with
status: "skipped".
If the user picks Yes, help me install it, run the flow that matches integration_method:
- mcp — propose the canonical MCP server for
{task_manager_slug} (Linear → @modelcontextprotocol/linear style entry, GitHub → @modelcontextprotocol/github, etc.; if you're not certain of the exact package, ask the user to confirm the package name rather than guessing). Show the user the proposed .mcp.json server entry, ask which env vars they need (API key, workspace id), and only after they confirm append the entry to .mcp.json (preserving existing servers — never rewrite the whole file). Do not write secrets into .mcp.json; reference them via env vars and tell the user where to set them. After writing, ask the user to reload the MCP server (usually by restarting Claude Code) and confirm before continuing.
- cli — detect the platform (
win32 on this user's machine, but check anyway). Propose the install command (winget install …, scoop install …, brew install …, npm i -g …, etc.) and ask the user to confirm before running. Run via Bash. After install, re-run command -v <cli> / where <cli> to verify.
- plugin — ask the user for the plugin or marketplace name. If it's a Claude Code plugin, point them at
/plugin to install it; do not try to install plugins from inside this skill. Wait for the user to confirm the plugin is loaded, then re-check availability.
After install (or after the user says they've installed it themselves), re-run the availability check from the top of 2b. If it still fails, ask the user whether to retry, switch integration method (jump back to 2a), or skip (return with status: "skipped"). Do not loop more than 3 retries without offering to skip.
Step 3 — find the tasks
Ask the user via AskUserQuestion (free-text "Other" channel) one open-ended question:
How do I fetch the open tasks for this repo from {task_manager_label} via {integration_method}? Tell me everything I need: the tool/command/endpoint, the project/team/workspace, and any filters. Examples:
- mcp: "call
mcp__linear__list_my_issues with team=ENG"
- cli: "run
gh issue list --repo acme/web --assignee @me --state open --json number,title,body"
- plugin: "run
/my-tasks for the web workspace"
- api: "POST
https://api.linear.app/graphql with LINEAR_API_KEY, query my open issues in team ENG"
Prefer search / name-based filters over internal ids. When the user offers a filter, push for the human-readable form (project name, team key, status name, assignee email/handle, repo owner/name) rather than an opaque uuid or numeric id. Ids drift, get re-issued, and are unreadable in the baked-in skill; names survive. Only fall back to an id if the manager genuinely doesn't expose a stable name-based filter for that field. If the user's first reply uses ids, ask once whether an equivalent name/key filter exists before recording.
Record the full reply as task_fetch_instructions (free-text). Then try it based on integration_method:
- mcp — invoke the MCP tool the user named with the args they described. If the arg shape is unclear, call with the obvious mapping and let the error guide a fix.
- cli — run the exact command via Bash.
- plugin — invoke the slash command or skill via the Skill tool.
- api — issue the HTTP request via
curl (or Python) using the env vars the user named.
If the call succeeded
Show a short preview (first 3 task titles or trimmed response). Ask via AskUserQuestion:
I fetched {N} task(s) from {task_manager_label}. Look right?
Options:
- Yes (or empty but the call succeeded — write it anyway) — proceed to Step 4.
- No, fix and retry — ask the user what to change, update
task_fetch_instructions, re-try.
If the call failed
Show the user the error and suggest the most likely cause — usually configuration. Map the failure shape to a hypothesis:
- Auth / 401 / 403 → missing or wrong env var (e.g.
LINEAR_API_KEY, GITHUB_TOKEN, JIRA_API_TOKEN). Ask the user to set it, then retry.
- 404 / not found / empty for a known-non-empty list → wrong scope (project/team id, repo path, workspace). Ask the user to correct.
- Tool / command / endpoint not found → integration not actually installed; loop back to Step 2b.
- Schema / validation / "unknown argument" → wrong arg shape for the tool/command. Show the error and ask the user to adjust the invocation.
- Network / DNS / timeout → connectivity. Pause and retry once before escalating to the user.
After the user adjusts, re-run the call. Cap the loop at ~5 retries; if it still doesn't work, offer status: "skipped".
Whatever instructions actually produced a successful fetch are what get baked into the helper skill in Step 4 — so do not move on until the call works (or the user accepts an empty-but-successful response).
Step 4 — write the helper skill
Now that the fetch works, generate .claude/skills/claude-slack-bridge_list-tasks/SKILL.md directly (no external template — write the file from scratch using the values you collected).
Create .claude/skills/claude-slack-bridge_list-tasks/ if missing, then write SKILL.md with this exact shape (atomic write: .SKILL.md.tmp → os.replace):
---
name: claude-slack-bridge_list-tasks
description: "List the open tasks assigned to the current user from {task_manager_label} via {integration_method}. Returns a list of task names only (no ids, URLs, or descriptions) for the /process clarification skill."
---
# claude-slack-bridge_list-tasks — fetch open tasks from {task_manager_label}
This skill is invoked by the `/process` clarification skill via the Skill tool. Its only job is to fetch the current user's open tasks from {task_manager_label} and return their names.
## How to fetch
Task manager: **{task_manager_label}** (`{task_manager_slug}`)
Integration method: **{integration_method}**
Run the following exactly as recorded during `/process-setup`:
{task_fetch_instructions}
## Output
Return **only the task names / titles**, one per line. Do not include ids, keys, numbers, URLs, descriptions, status, assignees, or any other metadata — just the names.
If the fetch returns zero tasks, say so explicitly rather than returning an empty response. If the fetch fails, surface the error verbatim — do not silently swallow it; the caller needs to know the integration broke.
Substitute the values inline as you write the file (do not leave {task_manager_label} etc. literally in the output):
{task_manager_label} → the label from Step 1 (e.g. Linear)
{task_manager_slug} → the slug from Step 1 (e.g. linear)
{integration_method} → from Step 2a (mcp / cli / plugin / api)
{task_fetch_instructions} → the exact instructions from Step 3 that produced a successful fetch (preserve formatting — code fences, command lines, tool names)
The frontmatter name must be exactly claude-slack-bridge_list-tasks so the /process skill can invoke it via the Skill tool.
Step 5 — run the generated skill end-to-end
After writing the file, invoke the freshly written claude-slack-bridge_list-tasks skill via the Skill tool to confirm it actually works as a skill (not just as the loose calls from Step 3). This catches issues like wrong frontmatter name, the skill not being picked up, or broken template substitution.
Show the user a short preview of the result and ask via AskUserQuestion:
The generated claude-slack-bridge_list-tasks skill returned {N} task(s). Look right?
Options:
- Yes — return with
status: "configured".
- No, fix and retry — diagnose (template substitution? wrong instructions baked in?), edit
.claude/skills/claude-slack-bridge_list-tasks/SKILL.md directly or loop back to Step 3, then re-run Step 5.
- Skip — return with
status: "skipped" (and consider removing the half-broken helper skill file).
Cap retries at ~3. Only return status: "configured" after the user confirms the generated skill works.
Return shape
End your final reply with a single fenced JSON block so the caller can parse the result.
For the configured case:
{
"status": "configured",
"task_manager_label": "Linear",
"task_manager_slug": "linear",
"integration_method": "mcp"
}
For the skipped case:
{
"status": "skipped"
}