跳到正文
cccskills
免费在 GitHub 公开

kortix-slack

Connect Slack to Kortix and handle team conversations through the Slack CLI. Show live progress, send formatted replies, share files, and search messages, with thread binding that routes follow-up replies back to the same agent session.

中文简介正在准备中。当前显示英语简介。

原文查看原文说明

How to CONNECT Slack (one command — `kortix channels connect`, prints a one-click install link) and how to answer in Slack as a teammate. Covers the live plan-block stream (`slack step` with --detail/--output, `slack send` to finalize the answer), file uploads, posting to other channels/threads, reactions, search, message editing/deletion, and the tone the bot should use. Load this when the user asks to connect/set up Slack, when the turn is triggered from Slack (the prompt mentions a Slack workspace/channel/thread, or `$SLACK_CHANNEL_ID` is set in the env), when this session messages someone in Slack and needs their reply to come back (thread binding, `slack bind-thread`), or when the user asks how to do anything in Slack.

查看安装方法

适用场景

  • Connect a Slack workspace to Kortix
  • Show task progress and results in a Slack thread
  • Share generated files in Slack
  • Route follow-up replies to the same agent session
  • Find messages in Slack

包含的文件(1)

  • SKILL.md28.9 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

<skill name="slack"> <overview> Your sandbox is wired into Slack. When a teammate `@`-mentions the bot or replies in a thread the bot owns, the platform spins up this session and hands you the message; your turn IS the Slack reply.

The slack CLI is on $PATH and just works — every call runs through the Kortix connector gateway, which resolves the Slack bot token server-side. There is no token in your sandbox and nothing to configure: don't look for $SLACK_BOT_TOKEN, don't reach for an MCP/HTTP workaround, just run the commands below. They are the full, supported surface (posting, file upload, history, reactions, search, edit/delete — all of it). Two patterns matter most:

  • slack step "..." — narrate progress. Updates the live plan block in the Slack thread as you go.
  • slack send "..." — finalize the turn with your answer. This closes the plan block and posts the reply.

Everything else (slack history, slack react, slack send --file, slack search, …) is for when the task explicitly asks for it. </overview>

<thread-binding> ### A reply comes back to you ONLY if its thread is bound to THIS session

Every Slack thread routes to exactly one Kortix session. A human reply in a thread goes to the session that thread is bound to. A reply in an unbound thread starts a new session: the user answers, and you never see it.

slack send --channel binds for you. When this session posts with --channel (a DM, a channel, a reply in a thread), the platform binds that thread to this session. The command output tells you the result:

slack send --channel U0123ABCD --text "Can you approve the deploy?"
# {"ok": true, "ts": "1700000000.000100", "channel": "D0123ABCD",
#  "thread_binding": {"bound": true, "thread_ts": "1700000000.000100", "session_id": "<this session>"}}

Every slack send --channel prints thread_binding. Read it whenever you expect an answer. Anything but bound: true carries a hint with the next command. Act on it:

thread_bindingMeaningWhat to do
bound: trueIn a channel, a reply that @mentions the bot comes back to this session as your next turn. In a DM, every reply does.Tell the user you asked in Slack and, in a channel, to @mention the bot in the thread to answer. Then end the turn. Do not poll.
bound: false, reason: thread_bound_to_another_session, owner_session_idAnother session of this project owns the thread. Replies go there, not here.To take it over: slack bind-thread --channel <channel> --thread <thread_ts> --force. Otherwise post a NEW top-level message (slack send --channel <id> without --thread).
bound: false, reason: thread_owned_by_another_user / thread_owned_by_another_projectAnother person's session, or another project, owns the thread. --force cannot move it.Post a NEW top-level message.
bound: false, reason: workspace_unknown / bind_failedThe bind was not written. Replies will start a new session.Run slack bind-thread --channel <channel> --thread <thread_ts> once. If it fails, tell the user replies will not reach this session.
bound: false, reason: top_level_fileA top-level --file post has no thread to bind.Post a text message with slack send --channel if you expect a reply.
bound: "unknown", reason: not_reportedThe API did not report a binding.Run slack bind-thread --channel <channel> --thread <thread_ts> and read its result.

slack bind-thread — check or bind a thread explicitly

slack bind-thread --channel <id> --thread <ts> binds a thread this session did not start (for example a thread a human started), and doubles as the check "is this thread mine?":

  • {"ok": true, "bound": true, "session_id": "<this session>"} — the thread is yours (already, or now).
  • exit 1, status: 409 — another session owns the thread; the error names it. The default never takes a thread over.
  • --force moves the thread to this session: {"bound": true, "rebound_from": "<old session>"}. It works only when both sessions belong to the same project and were started by the same user. Otherwise it fails with status: 403 (THREAD_OWNED_BY_ANOTHER_USER / THREAD_OWNED_BY_ANOTHER_PROJECT). After a move, replies stop reaching the old session — use --force only when the user wants this session to own the conversation.

Rules:

  • Tell the human to reply IN THE THREAD. A top-level message in the DM or channel is a new thread and starts a new session. In a channel, the reply must @mention the bot to reach the session. A DM needs no mention.
  • slack send --file --thread <ts> binds that thread; a top-level --file post binds nothing.
  • Answer a bound reply with slack send "<answer>". The reply opened a Slack turn in this session, so the plain answer form works. </thread-binding>
<connecting> ### "Connect my Slack" = ONE command. Nothing else.

If the project isn't wired to Slack yet (or the user asks to connect/set up Slack), run:

kortix channels connect

On Kortix Cloud this prints a one-click "Add to Slack" install link. Your entire job is: surface that URL to the user and tell them to open it, pick their workspace, and click Allow. That's the whole setup — the platform's shared Slack app handles the webhook, tokens, and connector materialization automatically. Verify afterwards with kortix channels status (or run kortix channels connect --wait to block until the install lands).

Do NOT:

  • walk the user through creating a Slack app at api.slack.com,
  • print or paste the app manifest,
  • ask for a bot token or signing secret,
  • mint a secret-intake link for SLACK_BOT_TOKEN/SLACK_SIGNING_SECRET,
  • try kortix connectors add slack (the slug is reserved; it will be rejected).

The manual path exists ONLY for self-hosted servers without the shared Slack app — and kortix channels connect detects that case itself and prints the manual instructions (kortix channels manifest + --manual). Trust its output; don't pre-empt it. </connecting>

<live-stream> The Slack message you're replying to has a live "plan block" attached. Each `slack step` you emit appears as a new checkpoint in that block in real time. Users can see what you're doing without waiting for the final answer.

slack step "<title>" — emit a checkpoint

Call this before each major step of your work. Keep titles short, human, and present-tense. A few per task — not one per shell command.

slack step "Reading the incident logs"
slack step "Cross-referencing with the deploy timeline"
slack step "Drafting the post-mortem"

--detail "<subtitle>" — short context line under the title

Use --detail to add a one-line subtitle that explains what specifically you're doing in this step. Shown while the step is in_progress.

slack step "Reading the incident logs" --detail "Last 24h, severity >= warn"

--output "<result>" — concrete result attached to the PREVIOUS step

When you start a new step and the previous one produced a concrete result, surface it with --output. It attaches to the step that's closing — the one transitioning to complete.

slack step "Cross-referencing with the deploy timeline" \
  --output "Found 47 ERROR lines clustered around 14:32 UTC"

slack step "Drafting the post-mortem" \
  --output "3 candidate deploys in the window; api@a3f1 looks suspicious"

Inline links inside --detail / --output

Use Slack mrkdwn link syntax <https://… |label> (NOT Markdown [label](url)). Slack server-parses these into proper rich-text link elements rendered inside the task card:

slack step "Reading the incident logs" \
  --detail "Pulling from <https://datadog.example.com/dash/api-errors|Datadog API errors>"

slack step "Cross-referencing the timeline" \
  --output "Tied to <https://github.com/acme/api/commit/a3f1|api@a3f1> — auth middleware"

People and channels in a step

A step never notifies anyone. <@U0123ABCD> in a step's title, --detail or --output shows as the person's name (@Sam Rivera), and <!here> shows as text. <#C0123ABCD> shows as the channel. To notify someone, mention them in slack send.

--source URL|TITLE — citation footer (repeatable)

Attach structured citations to the closing task. Slack renders them as a sources strip under that task's card. Pass multiple --source lines separated by newlines (use shell heredoc or repeat the flag in a wrapper).

slack step "Drafting the post-mortem" \
  --output "3 candidate deploys" \
  --source $'https://github.com/acme/api/commit/a3f1|api@a3f1
https://datadog.example.com/dash/api-errors|Datadog dashboard'

Up to 8 sources per task, titles auto-trim at 80 chars.

So the natural pattern, end-to-end, looks like:

slack step "Reading the incident logs" --detail "Last 24h, severity >= warn"
# ... do the work ...
slack step "Cross-referencing the deploy timeline" \
  --output "47 ERROR lines around 14:32 UTC" \
  --detail "Walking back from the first error"
# ... do the work ...
slack step "Drafting the post-mortem" \
  --output "Pinned to api@a3f1 — auth middleware change" \
  --detail "Writing root cause + remediation"
# ... do the work ...
slack send "It was api@a3f1 — the new auth middleware drops the trace header on retries. Reverting now."

Rules

  • Use slack step to mark phase transitions, not every shell call. ~3–6 per turn is right for most tasks; one per bash is noise.
  • Set --detail and --output once per step. Re-sending them for the same step appends rather than replaces — surprising and ugly.
  • Keep them short. --detail and --output get truncated at 500 chars upstream; aim for one tight sentence.
  • Don't slack step after you've called slack send. The plan is closed. A later step exits non-zero with reason: turn_finalized.
  • A step that did not reach the thread FAILS — it never answers ok: true. slack step exits 1 with {"ok": false, "code": "STEP_NOT_RELAYED", "reason": "<why>", "error": "…<what to do>"}. Read reason, then act:
    • no_open_turn — this run was not started from Slack (a web prompt on a Slack-born session), or the turn was already closed. Keep working; if the user is waiting in a thread, post there with slack send --channel <id> --thread <ts>.
    • turn_finalized — you already answered this turn. One slack send per turn.
    • relay_request_failed — the Kortix API refused the relay (auth, 5xx, timeout). That is a platform problem, not a missing turn: retry once, then report it in the thread with --channel/--thread.
    • stream_open_failed / post_failed — Slack rejected the message. Continue; deliver the answer with slack send at the end. Never assume a step was seen when the command failed. </live-stream>
<keeping-the-stream-alive> ### A live run has no idle timeout — silence only hurts the user

The plan block is a posted message the server edits in place. It is not an open stream, so Slack cannot auto-fail it. A long, silent step (a build, a test suite, a task/subagent) does not paint an error and does not end your run. The server closes a thread on its own only when your run has ended and no slack send reached the thread within 30 minutes. That thread then shows "This run ended without a reply."

Do not run heartbeat loops (while sleep …; do slack step …; done). They buy nothing, and a loop left running after slack send is a leak.

A wall of nothing for ten minutes is still bad UX:

  • Post a step before anything slow — git clone, pnpm install, a test suite, a build, pnpm preview, deep research, a big LLM call, a task/subagent — so the thread shows what you are waiting on.
  • Narrate long work in phases. slack step "Installing deps" → slack step "Running typecheck" → slack step "Running tests" reads better than one silent 12-minute block.
  • Space steps at real phase boundaries. Ten steps in two seconds add noise, not information. </keeping-the-stream-alive>
<final-answer> ### `slack send "<text>"` — plain-text answer

For a one-liner, post directly:

slack send "Reverted api@a3f1. Errors are back to baseline — auth header is now preserved on retry."

This finalizes the live stream and renders the message below the plan block.

slack send --blocks-file <path> — Block Kit answer (preferred for structure)

When the response has real structure — sections, headers, lists, links, citations — ship it as Block Kit. Slack accepts a closing blocks chunk on chat.stopStream, so the rich layout renders inline below the plan block. Always pair --blocks-file (or --blocks) with --text for the notification fallback.

Write the JSON to a temp file, then send:

cat > /tmp/answer.json <<'EOF'
[
  { "type": "header", "text": { "type": "plain_text", "text": "Incident summary" } },
  { "type": "section", "text": { "type": "mrkdwn", "text": "*Root cause:* <https://github.com/acme/api/commit/a3f1|api@a3f1> — the new auth middleware drops the trace header on retries." } },
  { "type": "divider" },
  { "type": "section", "fields": [
      { "type": "mrkdwn", "text": "*Impact*\n14:32–14:51 UTC\n~3% of API requests" },
      { "type": "mrkdwn", "text": "*Action*\nReverted, deploying now" }
  ] },
  { "type": "context", "elements": [
      { "type": "mrkdwn", "text": "Sources: <https://datadog.example.com/dash/api-errors|Datadog>  ·  <https://github.com/acme/api/pull/8421|Revert PR>" }
  ] }
]
EOF

slack send --text "Reverted api@a3f1 — root cause was the auth middleware" --blocks-file /tmp/answer.json

Use Block Kit when ANY of these apply:

  • The answer has 2+ distinct sections (root cause + impact + action, or summary + details + sources).
  • You're presenting comparisons, tables, or lists of items.
  • The answer should cite multiple sources prominently.
  • The response benefits from a clear title (use a header block).

Use plain slack send "..." when the answer is short prose with no structure.

Block Kit cheat sheet

Common block types the agent uses most:

BlockUse for
header (plain_text)Title of the answer
section (mrkdwn)Most prose, including `<url
section with fields2-column key/value layout (max 10 fields)
dividerVisual break between sections
context (mrkdwn)Small footer text, sources, timestamps
image (image_url + alt_text)Charts, screenshots — needs a public URL
actions (buttons / select menu)Inline interactivity for follow-ups
carousel (of card elements)Side-scrollable gallery — see below

Carousel of cards — for presenting a list of choices/items

When the answer is a list of things the user might pick between or browse (deploy candidates, repo search hits, scheduled meetings, design variants), a carousel of cards reads way better than a markdown list. Each card has an icon, a hero image, title/subtitle, body, and one or more buttons.

Important constraints (Slack rules, not ours):

  • Cards live ONLY inside a carousel block.
  • Cards support body (mrkdwn) and actions (buttons / select menus) — they do NOT support input / radio_buttons / checkboxes. To ask the user to choose, use the question tool instead.
  • Each card's button click fires a block_actions interaction; the platform routes it back as a follow-up Slack message (Picked: <button label>) into the same thread, the agent's next turn starts from that.
  • 2–10 cards per carousel.

Example — presenting 3 deploy candidates:

[
  { "type": "section", "text": { "type": "mrkdwn", "text": "*Three deploy candidates* — pick one to ship:" } },
  {
    "type": "carousel",
    "elements": [
      {
        "type": "card",
        "block_id": "deploy_a3f1",
        "icon": { "type": "image", "image_url": "https://github.com/acme.png?size=36", "alt_text": "acme" },
        "title":    { "type": "mrkdwn", "text": "*api@a3f1* — Production-ready" },
        "subtitle": { "type": "mrkdwn", "text": "2 commits ahead of main · ✓ tests pass" },
        "hero_image": { "type": "image", "image_url": "https://opengraph.githubassets.com/1/acme/api", "alt_text": "diff" },
        "body": { "type": "mrkdwn", "text": "Auth middleware retry fix + new metric. Safe to ship — small surface area, full coverage." },
        "actions": [
          { "type": "button", "style": "primary", "text": { "type": "plain_text", "text": "Deploy this" }, "action_id": "deploy_a3f1", "value": "a3f1" },
          { "type": "button", "text": { "type": "plain_text", "text": "View diff" }, "url": "https://github.com/acme/api/compare/main...a3f1" }
        ]
      },
      { "type": "card", "block_id": "deploy_b27e", "title": { "type": "mrkdwn", "text": "*api@b27e* — Needs review" }, "subtitle": { "type": "mrkdwn", "text": "12 commits ahead · ⚠️ 1 failing flake" }, "body": { "type": "mrkdwn", "text": "Bigger release: rate-limiter rework + Stripe webhook fix. Flake is in webhook tests." }, "actions": [ { "type": "button", "text": { "type": "plain_text", "text": "Deploy this" }, "action_id": "deploy_b27e", "value": "b27e" }, { "type": "button", "text": { "type": "plain_text", "text": "Hold" }, "style": "danger", "action_id": "hold_b27e", "value": "b27e" } ] },
      { "type": "card", "block_id": "deploy_c901", "title": { "type": "mrkdwn", "text": "*api@c901* — Hotfix only" }, "subtitle": { "type": "mrkdwn", "text": "1 commit · auth header preserve" }, "body": { "type": "mrkdwn", "text": "Minimal fix for the 14:32 incident. Lowest risk." }, "actions": [ { "type": "button", "style": "primary", "text": { "type": "plain_text", "text": "Deploy this" }, "action_id": "deploy_c901", "value": "c901" } ] }
    ]
  }
]

Ship it the same way as any Block Kit answer:

slack send --text "Pick a deploy candidate" --blocks-file /tmp/candidates.json

When to reach for carousel:

  • 2–6 items the user is choosing between, each with non-trivial context (subtitle, body, hero image).
  • The agent expects the user's button click to become the next prompt, not a fill-in form.

When NOT to:

  • For plain choices with no card-worthy context (use question instead).
  • For 1 item (just a section) or 7+ items (split, paginate, or summarize).
  • For a quick yes/no (use question).

Full Block Kit reference: https://docs.slack.dev/reference/block-kit/blocks/

Tone (applies to either mode)

Reply like a colleague messaging on Slack:

  • No preamble. Don't open with "Sure!" / "I've taken a look and…". Get to the answer.
  • Slack mrkdwn. *bold* (single asterisks), _italic_, `code`, ```code blocks```. Markdown-style **bold** renders as literal asterisks — don't use it.
  • Short. A few sentences > a wall of text. Use bullet lists for ≥3 items.
  • Link with <url|text>. Slack's syntax, not Markdown [label](url).
  • No XML / no "Here's a summary:" headers. This is a chat message, not a report.

One slack send per turn

Each turn finalizes exactly one stream. Don't call slack send twice — the second call exits 1 with reason: turn_finalized because the stream is already closed. If you need to deliver multiple things, fold them into one Block Kit message or use slack send --channel ... for sibling posts.

When slack send fails

A slack send with no --channel is the turn's answer. When it cannot be delivered into a Slack turn it exits 1 with {"ok": false, "code": "ANSWER_NOT_RELAYED", "reason": "<why>", "error": "…<what to do>"} — it never prints ok: true for an undelivered answer. no_open_turn means this run was not started from Slack, or the turn was closed before you answered; if the user is waiting in a thread, deliver the same answer with slack send --channel <id> --thread <ts> (the channel and thread are in the prompt header and in $SLACK_CHANNEL_ID / $SLACK_THREAD_TS). relay_request_failed is a Kortix API failure, not a missing turn: retry once, then post with --channel/--thread.

A reminder fire is not a Slack turn either. When you set a reminder (kortix remind) from a Slack thread, write the channel id and thread ts into the reminder text — e.g. kortix remind "Check whether the deploy finished; post the result with slack send --channel C0123ABCD --thread 1727600000.000100" --in 30m — and answer the fire with slack send --channel <id> --thread <ts>. A plain slack send on that turn exits 1 with no_open_turn. </final-answer>

<asking-the-user> ### Use the built-in `question` tool — Slack renders the buttons

Rule: if your reply asks the user to choose, call the question tool. Never put a list of choices inside slack send.

slack send finalizes the turn and closes the live stream — once it fires, the user can only reply with free text. A list of choices written into it cannot be clicked.

When the turn is Slack-triggered, the Kortix server posts the question(s) into the thread: each question in bold, the option descriptions listed under it, and one clickable button per option. The tool returns at once with a note telling you to end your turn — it does not block, and it does not return the user's answer. END the turn.

The answer arrives as your NEXT turn, with full context:

  • a button click → Answering your question "<question>": and the picked label;
  • a reply typed in the thread → the message itself.
When you want to…Use
Ask the user to choosequestion tool
Ask something genuinely open-endedslack send with the question
Deliver the final answer / summaryslack send
Show progress along the wayslack step
Post a separate message to another channelslack send --channel ...

Calling the question tool

Per the tool's schema, every option has a label (1–5 words) and a description:

{
  "questions": [
    {
      "question": "Which environment should I deploy to?",
      "header": "Environment",          // short label (max 30 chars)
      "options": [
        { "label": "Production", "description": "Live traffic; needs a rollback plan" },
        { "label": "Staging",    "description": "Mirrors prod data; safe to break" },
        { "label": "Dev",        "description": "Sandbox; no real users" }
      ]
    }
  ]
}

Rules

  • One question per call when the answers depend on each other. Each click starts its own turn and carries one answer. Several questions in one call post several rows of buttons, and the user clicks them one at a time.
  • multiple and custom change nothing in Slack. Every option is a one-click button, and a reply typed in the thread always works.
  • Put the tradeoff in description. A button shows only its label; the descriptions are listed above the buttons.
  • Skip trivial yes/no when context implies the answer. Ask only what blocks you — not "are you sure?" rituals. </asking-the-user>
<files-and-artifacts> ### Uploading files: `slack send --file <path> --channel <id>`

File upload is fully supported — slack send --file is the way. When the work produces an artifact (a PDF, a CSV, a report, a diff, a screenshot), upload it with --file instead of pasting the contents or improvising. Do not conclude "uploads aren't supported", and do not reach for the connector MCP, a manual files.getUploadURLExternal call, or an HTTP-host-a-link hack — --file already does the multi-step upload for you, server-side. It requires a --channel and (typically) a --thread so it lands under the answer:

slack send \
  --channel "$SLACK_CHANNEL_ID" \
  --thread  "$SLACK_THREAD_TS" \
  --file    /workspace/output/report.md \
  --text    "Full report ↓"

$SLACK_CHANNEL_ID and $SLACK_THREAD_TS are pre-set on Slack-triggered turns. Use them.

Note: slack send --file ... posts a separate message — it does NOT count as the turn's finalizing answer. Combine it with a regular slack send "..." to also close the stream:

slack send --channel "$SLACK_CHANNEL_ID" --thread "$SLACK_THREAD_TS" \
  --file /workspace/output/report.md --text "Full report attached."
slack send "Pulled 12,847 sign-ups, grouped by source. CSV above."
</files-and-artifacts> <other-surfaces> Reach for these only when the task explicitly asks for them.

Read prior thread context

slack history --channel "$SLACK_CHANNEL_ID" --limit 20            # the channel's recent messages
slack thread  --channel "$SLACK_CHANNEL_ID" --ts "$SLACK_THREAD_TS"  # this thread's replies

Each message carries user, the author's id, and user_name, the author's display name when Slack has one. Write people's names from user_name in an answer. Use <@user> only to mention someone, because a mention notifies them.

Reads and writes stay inside this project

Every Kortix project in a Slack workspace shares one bot, so reads reach only this project's conversations: the channels and DMs connected to it, and the threads its sessions started or joined. slack history, slack thread, slack channel-info, slack file-info and slack search refuse anything else with conversation_not_in_project, and slack channels lists public channels plus this project's private ones.

Writes never act inside another project's channel or thread: slack send (text or --file), slack edit, slack delete, slack react, slack unreact, slack join and slack bind-thread refuse them with the same conversation_not_in_project. A channel no project is connected to and a DM with a person are fine. Pass --channel as the id (C0123ABCD, or a user id U0123ABCD for a DM), never a channel name.

On that error, do not retry with another id. Tell the user what the error message says: the conversation belongs to another project, or they can connect it by running /kortix switch in it.

React to a message

slack react   --channel "$SLACK_CHANNEL_ID" --ts "$SLACK_TRIGGER_TS" --emoji "white_check_mark"
slack unreact --channel "$SLACK_CHANNEL_ID" --ts "$SLACK_TRIGGER_TS" --emoji "eyes"   # remove one you added

A "seen it" reaction (eyes, hourglass, thinking_face, …) is temporary. The platform already marks the message ⏳ while you work, so you rarely need one. If you add one, remove it with slack unreact right after slack send. A marker left behind reads as "still working" forever.

Post to a different channel (announcements, cross-posts)

slack send --channel "C0123ABCD" --text "Heads up: rolled api@a3f1 forward."

A channel of another Kortix project refuses the post (see "Reads and writes stay inside this project").

Edit / delete a message you posted earlier

slack edit   --channel "$SLACK_CHANNEL_ID" --ts "<msg_ts>" --text "Updated answer."
slack delete --channel "$SLACK_CHANNEL_ID" --ts "<msg_ts>"

Search the workspace

slack search --query "deploy api@"

Look up users / channels

slack users
slack user        --id "U0123ABCD"
slack channels
slack channel-info --channel "C0123ABCD"
slack me

Download a file shared in the thread

slack file-info --file "F0123ABCD"
slack download  --url "<file.url_private>" --out /workspace/incoming/x.png

Full help: slack help. </other-surfaces>

<gotchas> - **`*bold*` not `**bold**`.** Slack uses single asterisks. Double-asterisk markdown renders as literal asterisks. - **`--detail` and `--output` are append-not-replace per step.** Set each only once on the step that owns it. If you need to revise, advance to a new step. - **`slack step` after `slack send` drops silently.** Plan block is closed once the answer ships. Always send the answer last. - **`slack send --file` does NOT finalize the stream.** It posts a separate file message. Follow it with a regular `slack send "..."` to close the turn. - **`$SLACK_CHANNEL_ID`, `$SLACK_THREAD_TS`, `$SLACK_TRIGGER_TS` are pre-injected on Slack turns.** Use them — don't hard-code IDs. - **Stay in the thread.** Unless the task explicitly says "post in #channel-X", everything goes in the originating thread. Cross-posting to other channels needs a real reason (incident broadcast, scheduled digest). - **Clean up your temporary reactions.** An `eyes` (or other "working") reaction you added stays on the message until you `slack unreact` it. Remove it once you have replied. - **The user can hit Stop.** A red Stop button sits under the plan block; the user can click it any time. If you see the turn end abruptly, that's why — don't retry automatically. </gotchas> </skill>

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

Review Slack access requests against Okta role and team information, then prepare narrowly scoped GitHub or AWS IAM permissions. Apply changes only after an eligible person's approval and record the grant, reasoning, approver, and timestamp.

中文简介正在准备中。当前显示英语简介。

  • Reviewing GitHub repository access requests from Slack
  • Preparing AWS IAM permissions for a specific task
  • Routing sensitive access requests for additional review
kortix-ai/suna2万2026年10月22日 更新

Research companies and people before outreach or meetings. Combines business profiles, recent news, hiring signals, and key contacts into a sourced brief with talking points and suggested questions, adding relationship history when CRM data is connected.

中文简介正在准备中。当前显示英语简介。

  • Research a prospective customer before outreach
  • Prepare background information for meeting attendees
  • Compare a competitor's products and positioning
kortix-ai/suna2万2026年10月22日 更新

Review daily Google Ads and Meta Ads results for budget pacing, declining performance, and unusual activity. Get prioritized findings with supporting numbers and concrete recommendations for a marketing team to assess and carry out.

中文简介正在准备中。当前显示英语简介。

  • Checking whether campaign budgets are being spent on schedule
  • Investigating rising acquisition costs or falling ad returns
  • Finding ads and keywords that spend without converting
kortix-ai/suna2万2026年10月22日 更新

Automate website tasks such as navigating pages, filling forms, clicking buttons, taking screenshots, and extracting data. The skill also supports web app testing, with specialized guides for Electron desktop apps, Slack, and cloud browsers.

中文简介正在准备中。当前显示英语简介。

  • Automate form entry and page navigation
  • Capture screenshots and extract page data
  • Explore web apps for bugs
kortix-ai/suna2万2026年10月22日 更新

Process emailed vendor invoices by extracting details, comparing them with purchase orders and invoice history, and recording duplicates, overcharges, or missing orders. Summarize results in Slack for human review; payment approval and execution remain with people.

中文简介正在准备中。当前显示英语简介。

  • Checking incoming invoices against purchase orders
  • Finding duplicate invoices and likely resends
  • Reviewing unit prices and remaining order balances
kortix-ai/suna2万2026年10月22日 更新

billing

免费

Guide changes to Kortix billing code, admin controls, and pricing screens. Explain how plans, trials, enterprise contracts, and access exceptions should work, where pricing is defined, and which audited routes must handle account changes.

中文简介正在准备中。当前显示英语简介。

  • Update billing logic and its specification together
  • Review how trials and enterprise contracts are handled
  • Find the code that defines prices and allowances
kortix-ai/suna2万2026年10月22日 更新

查看 kortix-ai 的全部技能

报告此技能的问题