From d59fb64f1f215adb23851c01b61209f600658ee4 Mon Sep 17 00:00:00 2001 From: Bruno Bornsztein Date: Fri, 29 May 2026 09:25:08 -0500 Subject: [PATCH 1/2] docs: add ty-slack sidecar exploration/proposal (task #3723) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Answers two questions from the Slack screenshot in task #3723: 1. Did we already build this? No. The only prior "Slack" work (PR #433, task #1172) was marketing copy, not an integration. Closest precedent is the ty-email sidecar (#371/#385); PR #402 circled the remote-MCP idea. 2. Does a Slack sidecar make sense? Yes — and ~90% of it already exists. Documents two patterns (chat-control sidecar vs hosted remote MCP), recommends building ty-slack as a near-clone of ty-email by reusing the existing CLI bridge, LLM classifier, ty serve HTTP API, and the events/hooks push mechanism. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/proposals/ty-slack-sidecar.md | 188 +++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 docs/proposals/ty-slack-sidecar.md diff --git a/docs/proposals/ty-slack-sidecar.md b/docs/proposals/ty-slack-sidecar.md new file mode 100644 index 00000000..a6d44a48 --- /dev/null +++ b/docs/proposals/ty-slack-sidecar.md @@ -0,0 +1,188 @@ +# Proposal: `ty-slack` — manage TaskYou from Slack (and other chat channels) + +> Status: exploration / recommendation +> Origin: Task #3723 — "Explore taskyou MCP sidecar extension for Slack" +> TL;DR: **Yes, this makes sense, and ~90% of it already exists.** Build a +> `ty-slack` sidecar in `extensions/`, modeled almost exactly on `ty-email`. +> We have **not** built this before — the only prior "Slack" work was a +> marketing message, not an integration. + +--- + +## 1. What prompted this + +The screenshot attached to the task shows a Slack thread in `#product` where +Bruno asks Claude (running in the cloud "Claude in Slack" integration) whether +it has access to the InfluenceKit TaskYou agents server. Claude answers **no**: + +> "I don't have access to a TaskYou agents server in this session. The MCP +> servers available to me are: GitHub MCP... that's a separate integration +> running in your Slack workspace — not something I can access from this remote +> execution environment." + +So the friction is concrete: **from Slack there is no way to see, create, or +unblock TaskYou tasks.** The question is whether a sidecar (like the ones we +already ship) should close that gap. + +## 2. Did we already build this? (short answer: no) + +| What I found | Relevance | +|---|---| +| PR #433 (closed) / commit `8b67f59` / archived task #1172 — *"Add tweet and Slack message for task queue improvements"* | **Not an integration.** This was marketing copy *about* TaskYou to post to Slack, not a way to drive TaskYou *from* Slack. | +| **PR #371 (merged)** + #385 — `ty-email` sidecar | **The direct precedent.** A full channel-based remote-control sidecar. A Slack version is a near-clone with a different adapter. | +| PR #402 (closed) — *"Review Cloudflare Code Mode MCP for TaskYou"* | Adjacent: explored exposing TaskYou's MCP server remotely. Relevant to "Pattern B" below. | +| `extensions/ty-web`, `extensions/ty-qmd` | Other sidecars showing the established `extensions/` pattern and the `ty serve` HTTP API + MCP-proxy patterns. | + +There is **no existing Slack control surface** and **no open issue/PR** for one. +`grep -ri slack` across the repo returns only the marketing commit. + +## 3. The two things "Slack integration" could mean + +These are genuinely different and worth separating, because the screenshot +actually depicts the *harder* one. + +### Pattern A — `ty-slack` sidecar (chat → TaskYou control channel) — RECOMMENDED + +A small daemon you run next to TaskYou. You DM or @-mention a Slack bot; it +classifies intent with an LLM and drives the `ty` CLI. It posts replies in-thread +and pushes a message when a task needs input or finishes. **This is the literal +analog of `ty-email`** and the most direct reading of "manage their taskyou +remotely via Slack." + +``` +Slack user ──@mention/DM──▶ Slack (Events API / Socket Mode) + │ + ▼ + ┌────────────┐ + │ ty-slack │──▶ LLM API (classify intent) + │ │──▶ ty CLI / ty serve API (act) + │ │──▶ chat.postMessage (reply) + └────────────┘ + ▲ + task.blocked / task.completed hook ──┘ (push notifications) +``` + +### Pattern B — hosted/remote MCP endpoint (what the screenshot shows) + +The cloud "Claude in Slack" wants to call `taskyou_*` MCP tools directly, but +TaskYou's MCP server (`internal/mcp/server.go`) is **stdio-only** — it reads +JSON-RPC off `os.Stdin`, is spawned per-task by Claude Code via `.mcp.json` +(`ty mcp-server --task-id`), and is not network-reachable. To let a remote +Claude use it you'd need a **network-exposed, authenticated MCP server** +(HTTP/SSE transport) wrapping the existing `ty serve` REST API, plus hosting and +tunneling. This is the bigger lift PR #402 was circling. + +**Recommendation:** ship Pattern A first. It delivers the user value ("manage +TaskYou from Slack") with infrastructure we already have, and it does not require +exposing anything to the public internet. Pattern B is a worthwhile follow-up but +is an infra/security project, not a sidecar. + +## 4. Why Pattern A is cheap: almost all the pieces exist + +`ty-slack` reuses TaskYou's existing seams. Concretely: + +1. **The CLI bridge already exists.** `extensions/ty-email/internal/bridge` + wraps `ty list/show/create/input/execute/output` with `--json`. It is not + email-specific — it should be lifted into a shared package (e.g. + `extensions/internal/bridge` or a `ty-core` module) and reused verbatim. + +2. **The intent classifier already exists.** `ty-email/internal/classifier` + uses a direct Claude API call (no permission prompts) to map a free-text + message → `{create | input | execute | query}`. Slack messages classify the + same way. Reuse it. + +3. **The HTTP API already exists.** `ty serve` (`internal/web/server.go`) + exposes the full surface — `GET/POST /api/tasks`, `/tasks/{id}/input`, + `/execute`, `/logs`, `/stream` (SSE), `/board`, projects, types. `ty-slack` + can call the CLI (like `ty-email`) *or* this API. The API is the better + choice if `ty-slack` runs on a different host than the daemon. + +4. **The push mechanism already exists.** `internal/events` emits + `task.blocked`, `task.completed`, `task.failed`, etc., and `internal/hooks` + runs a script named after each event with `TASK_EVENT` + task metadata in the + environment. A `task.blocked` hook that POSTs to `ty-slack` (or straight to a + Slack webhook) gives "ping me in Slack when a task needs input" for free — no + core changes. + +So the genuinely new code is small: a Slack **adapter** (Socket Mode or Events +API + `chat.postMessage`), thread↔task state tracking (mirror +`ty-email/internal/state`), and an `init` wizard for the bot token / signing +secret / allowed users. + +## 5. Proposed shape + +``` +extensions/ty-slack/ + cmd/main.go # cobra: init | serve | process | test | status | send + internal/adapter/ # Slack Socket Mode + Events API; chat.postMessage + internal/state/ # thread_ts ↔ task_id mapping (SQLite), dedupe + config.example.yaml + README.md +# shared (lifted out of ty-email so both reuse it): +extensions/internal/bridge/ # ty CLI / ty serve client +extensions/internal/classifier/ # LLM intent classification +``` + +Config mirrors `ty-email` (`~/.config/ty-slack/config.yaml`): + +```yaml +slack: + mode: socket # socket (no public URL) | events (needs HTTPS endpoint) + bot_token_cmd: echo $SLACK_BOT_TOKEN + app_token_cmd: echo $SLACK_APP_TOKEN # socket mode + signing_secret_cmd: echo $SLACK_SIGNING_SECRET # events mode + notify_channel: "#taskyou" # where blocked/done pings go +classifier: + provider: claude + api_key_cmd: echo $ANTHROPIC_API_KEY +taskyou: + cli: ty # or: api: http://localhost:8080 + dangerous: false +security: + allowed_users: # Slack user IDs allowed to drive TaskYou + - U012ABCDEF +``` + +### Interaction examples + +- `@taskyou fix the checkout 500s and run it` → creates + executes a task, + replies in-thread with the task id and a board link. +- Task hits a decision point → `ty-slack` posts *"Task #312 needs input: which + migration strategy?"* to `#taskyou`. Reply in that thread → routed to + `ty input 312 …`. +- `@taskyou what's happening with 312?` → posts recent `ty output 312`. + +## 6. Security notes (same model as `ty-email`) + +- **Allowlist by Slack user ID**, not just channel membership — only listed + users can create/execute tasks. +- **Verify request authenticity** — Slack signing-secret check (Events API) or + Socket Mode's authenticated socket; never act on unverified payloads. +- **No code execution from chat** — the LLM only *classifies*; the sidecar only + calls `ty` subcommands. `--dangerous` stays opt-in via config, exactly as in + `ty-email`. +- **Local secrets** — bot/app tokens resolved via `*_cmd` shell-outs, never sent + to the LLM. + +## 7. Recommendation + +1. **Build `ty-slack` (Pattern A)** as a sidecar in `extensions/`, refactoring + `ty-email`'s `bridge` and `classifier` into a shared package both consume. + This is a focused, low-risk follow-up — most of the surface area is proven. +2. **Defer Pattern B** (network-exposed MCP for cloud Claude) to a separate + spike; it's a hosting/auth project (pick up where PR #402 left off) and is not + required to let people drive TaskYou from Slack today. +3. The "ping me when a task is blocked/done" half can ship **immediately** as a + documented `task.blocked` / `task.completed` hook posting to a Slack incoming + webhook — independent of the full sidecar. + +## 8. Open questions for Bruno + +- **Hosting:** is `ty-slack` a thing each user runs next to their daemon (like + `ty-email`), or a single shared bot for the InfluenceKit workspace? Shared → + multi-user routing + per-user allowlists become the main design work. +- **Socket Mode vs Events API:** Socket Mode needs no public URL (simplest for a + laptop/agent server). Events API is better for an always-on shared bot but + needs an HTTPS endpoint. +- **Do we also want Pattern B** (remote MCP) so the *existing* cloud Claude-in- + Slack can call `taskyou_*` tools, or is a dedicated TaskYou bot enough? From cc121624655ff4d418b19900d1ac90e44211b1c7 Mon Sep 17 00:00:00 2001 From: Bruno Bornsztein Date: Mon, 8 Jun 2026 15:19:54 -0500 Subject: [PATCH 2/2] docs: fold taskyou-os prior art into ty-slack proposal (task #3723) Bruno pointed at github.com/taskyou/taskyou-os. It's the remote-management layer for TaskYou and already contains the closest precedent: a Linear poller module (modules/linear/linear-poll.mjs) that bridges Linear @agent comments -> ty create/execute -> posts diffs back. So we've now built this exact channel-bridge pattern twice (ty-email + Linear poller). Updated the proposal to: - recommend building Slack as a taskyou-os module (modules/slack, mirroring modules/linear), enabled via SLACK_ENABLED, tailing notifications.jsonl for push; ty-email Go sidecar kept as the fallback template - add a "where should it live" comparison (taskyou-os module vs extension) - note notifications.jsonl + the GM as the existing push substrate - link Pattern B (remote MCP) to the taskyou-os credential-proxy design Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/proposals/ty-slack-sidecar.md | 266 ++++++++++++++--------------- 1 file changed, 126 insertions(+), 140 deletions(-) diff --git a/docs/proposals/ty-slack-sidecar.md b/docs/proposals/ty-slack-sidecar.md index a6d44a48..ef82e3c7 100644 --- a/docs/proposals/ty-slack-sidecar.md +++ b/docs/proposals/ty-slack-sidecar.md @@ -1,188 +1,174 @@ -# Proposal: `ty-slack` — manage TaskYou from Slack (and other chat channels) +# Proposal: manage TaskYou from Slack (and other chat channels) > Status: exploration / recommendation > Origin: Task #3723 — "Explore taskyou MCP sidecar extension for Slack" -> TL;DR: **Yes, this makes sense, and ~90% of it already exists.** Build a -> `ty-slack` sidecar in `extensions/`, modeled almost exactly on `ty-email`. -> We have **not** built this before — the only prior "Slack" work was a -> marketing message, not an integration. +> TL;DR: **Yes, this makes sense — and we have already built the exact pattern +> twice** (the `ty-email` sidecar here, and the **Linear poller module** in +> [`taskyou-os`](https://github.com/taskyou/taskyou-os)). A Slack integration is +> a third instance of a well-trodden path. Recommended home: a **`taskyou-os` +> module** (`modules/slack/`, modeled on `modules/linear/`), with `ty-email` as +> the fallback template if we want a standalone Go sidecar instead. --- ## 1. What prompted this The screenshot attached to the task shows a Slack thread in `#product` where -Bruno asks Claude (running in the cloud "Claude in Slack" integration) whether -it has access to the InfluenceKit TaskYou agents server. Claude answers **no**: +Bruno asks Claude (the cloud "Claude in Slack" integration) whether it can reach +the InfluenceKit TaskYou agents server. Claude answers **no**: -> "I don't have access to a TaskYou agents server in this session. The MCP -> servers available to me are: GitHub MCP... that's a separate integration -> running in your Slack workspace — not something I can access from this remote -> execution environment." +> "I don't have access to a TaskYou agents server in this session… that's a +> separate integration running in your Slack workspace — not something I can +> access from this remote execution environment." -So the friction is concrete: **from Slack there is no way to see, create, or -unblock TaskYou tasks.** The question is whether a sidecar (like the ones we +The friction is concrete: **from Slack there's no way to see, create, or unblock +TaskYou tasks.** The question is whether a sidecar/integration (like the ones we already ship) should close that gap. -## 2. Did we already build this? (short answer: no) +## 2. Did we already build this? (No Slack — but we built the pattern twice) -| What I found | Relevance | -|---|---| -| PR #433 (closed) / commit `8b67f59` / archived task #1172 — *"Add tweet and Slack message for task queue improvements"* | **Not an integration.** This was marketing copy *about* TaskYou to post to Slack, not a way to drive TaskYou *from* Slack. | -| **PR #371 (merged)** + #385 — `ty-email` sidecar | **The direct precedent.** A full channel-based remote-control sidecar. A Slack version is a near-clone with a different adapter. | -| PR #402 (closed) — *"Review Cloudflare Code Mode MCP for TaskYou"* | Adjacent: explored exposing TaskYou's MCP server remotely. Relevant to "Pattern B" below. | -| `extensions/ty-web`, `extensions/ty-qmd` | Other sidecars showing the established `extensions/` pattern and the `ty serve` HTTP API + MCP-proxy patterns. | +No Slack control surface exists. But the relevant prior art is bigger than I +first thought — once you include `taskyou-os`, we have **two** working +external-channel → TaskYou bridges: -There is **no existing Slack control surface** and **no open issue/PR** for one. -`grep -ri slack` across the repo returns only the marketing commit. +| What exists | Where | Relevance | +|---|---|---| +| **`ty-email` sidecar** (PR #371 + #385) | `extensions/ty-email` | Channel-control sidecar: email in → LLM classify intent → `ty` CLI → reply/notify. The architectural twin of a Slack bot. | +| **Linear poller module** (`linear-poll.mjs`) | `taskyou-os/modules/linear` | **The closest precedent.** Polls Linear for `@agent` comments → `ty create/execute` → routes to projects by issue label → **posts diffs/results back** as Linear comments. State in `.linear-poll-state.json`, `LINEAR_TOKEN` auth, `.auth-failed` graceful degradation. A Slack module is a near-exact analog. | +| **`taskyou-os`** (the remote "OS") | whole repo | Local Claude Code **GM** session ↔ SSH ↔ remote server running `ty daemon` / `ty serve` / `ty-web` as systemd services. Agents write lifecycle events to **`notifications.jsonl`**, which the GM monitors to know when tasks complete or block. | +| Task event hooks (`task.blocked/completed/started.tmpl`) | `taskyou-os/templates/hooks` | The push substrate. Each hook appends a JSON record to `notifications.jsonl`. Mirrors `internal/events` + `internal/hooks` in this repo. | +| PR #433 / task #1172 — "tweet and Slack message" | this repo | **Not** an integration — marketing copy *about* TaskYou. The only thing `grep -ri slack` finds here. | +| PR #402 (closed) — "Review Cloudflare Code Mode MCP" | this repo | Adjacent: explored exposing TaskYou's MCP server remotely (see Pattern B). | + +So the honest answer: **we have not built Slack, but we've solved this exact +shape twice.** That makes a Slack integration low-risk and mostly a +copy-adapt-and-configure job, not new architecture. ## 3. The two things "Slack integration" could mean -These are genuinely different and worth separating, because the screenshot -actually depicts the *harder* one. +These are genuinely different, and the screenshot depicts the *harder* one. -### Pattern A — `ty-slack` sidecar (chat → TaskYou control channel) — RECOMMENDED +### Pattern A — a chat → TaskYou control bridge — RECOMMENDED -A small daemon you run next to TaskYou. You DM or @-mention a Slack bot; it -classifies intent with an LLM and drives the `ty` CLI. It posts replies in-thread -and pushes a message when a task needs input or finishes. **This is the literal -analog of `ty-email`** and the most direct reading of "manage their taskyou -remotely via Slack." +You DM or @-mention a bot in Slack; it classifies intent and drives `ty`, posts +replies in-thread, and pings you when a task needs input or finishes. This is the +literal analog of **both** `ty-email` and the **Linear poller**, and the most +direct reading of "manage their taskyou remotely via Slack." ``` -Slack user ──@mention/DM──▶ Slack (Events API / Socket Mode) +Slack user ──@mention/DM──▶ Slack (Socket Mode / Events API) │ ▼ - ┌────────────┐ - │ ty-slack │──▶ LLM API (classify intent) - │ │──▶ ty CLI / ty serve API (act) - │ │──▶ chat.postMessage (reply) - └────────────┘ + ┌──────────────┐ + │ slack module │──▶ LLM classify intent + │ (poller/ │──▶ ty CLI / ty serve API + │ socket) │──▶ chat.postMessage (reply) + └──────────────┘ ▲ - task.blocked / task.completed hook ──┘ (push notifications) + notifications.jsonl (task.blocked / completed) ──┘ push ``` -### Pattern B — hosted/remote MCP endpoint (what the screenshot shows) +### Pattern B — hosted/remote MCP endpoint (what the screenshot literally shows) The cloud "Claude in Slack" wants to call `taskyou_*` MCP tools directly, but TaskYou's MCP server (`internal/mcp/server.go`) is **stdio-only** — it reads JSON-RPC off `os.Stdin`, is spawned per-task by Claude Code via `.mcp.json` -(`ty mcp-server --task-id`), and is not network-reachable. To let a remote -Claude use it you'd need a **network-exposed, authenticated MCP server** -(HTTP/SSE transport) wrapping the existing `ty serve` REST API, plus hosting and -tunneling. This is the bigger lift PR #402 was circling. - -**Recommendation:** ship Pattern A first. It delivers the user value ("manage -TaskYou from Slack") with infrastructure we already have, and it does not require -exposing anything to the public internet. Pattern B is a worthwhile follow-up but -is an infra/security project, not a sidecar. - -## 4. Why Pattern A is cheap: almost all the pieces exist - -`ty-slack` reuses TaskYou's existing seams. Concretely: - -1. **The CLI bridge already exists.** `extensions/ty-email/internal/bridge` - wraps `ty list/show/create/input/execute/output` with `--json`. It is not - email-specific — it should be lifted into a shared package (e.g. - `extensions/internal/bridge` or a `ty-core` module) and reused verbatim. - -2. **The intent classifier already exists.** `ty-email/internal/classifier` - uses a direct Claude API call (no permission prompts) to map a free-text - message → `{create | input | execute | query}`. Slack messages classify the - same way. Reuse it. - -3. **The HTTP API already exists.** `ty serve` (`internal/web/server.go`) - exposes the full surface — `GET/POST /api/tasks`, `/tasks/{id}/input`, - `/execute`, `/logs`, `/stream` (SSE), `/board`, projects, types. `ty-slack` - can call the CLI (like `ty-email`) *or* this API. The API is the better - choice if `ty-slack` runs on a different host than the daemon. - -4. **The push mechanism already exists.** `internal/events` emits - `task.blocked`, `task.completed`, `task.failed`, etc., and `internal/hooks` - runs a script named after each event with `TASK_EVENT` + task metadata in the - environment. A `task.blocked` hook that POSTs to `ty-slack` (or straight to a - Slack webhook) gives "ping me in Slack when a task needs input" for free — no - core changes. - -So the genuinely new code is small: a Slack **adapter** (Socket Mode or Events -API + `chat.postMessage`), thread↔task state tracking (mirror -`ty-email/internal/state`), and an `init` wizard for the bot token / signing -secret / allowed users. - -## 5. Proposed shape - -``` -extensions/ty-slack/ - cmd/main.go # cobra: init | serve | process | test | status | send - internal/adapter/ # Slack Socket Mode + Events API; chat.postMessage - internal/state/ # thread_ts ↔ task_id mapping (SQLite), dedupe - config.example.yaml - README.md -# shared (lifted out of ty-email so both reuse it): -extensions/internal/bridge/ # ty CLI / ty serve client -extensions/internal/classifier/ # LLM intent classification -``` - -Config mirrors `ty-email` (`~/.config/ty-slack/config.yaml`): - -```yaml -slack: - mode: socket # socket (no public URL) | events (needs HTTPS endpoint) - bot_token_cmd: echo $SLACK_BOT_TOKEN - app_token_cmd: echo $SLACK_APP_TOKEN # socket mode - signing_secret_cmd: echo $SLACK_SIGNING_SECRET # events mode - notify_channel: "#taskyou" # where blocked/done pings go -classifier: - provider: claude - api_key_cmd: echo $ANTHROPIC_API_KEY -taskyou: - cli: ty # or: api: http://localhost:8080 - dangerous: false -security: - allowed_users: # Slack user IDs allowed to drive TaskYou - - U012ABCDEF -``` +(`ty mcp-server --task-id`), and is not network-reachable. Letting a remote +Claude use it needs a **network-exposed, authenticated MCP server** (HTTP/SSE +transport) wrapping the existing `ty serve` REST API, plus hosting/tunnel/auth. +This is the bigger lift PR #402 circled, and it overlaps with the +`taskyou-os` **credential-proxy** design +(`docs/plans/2026-03-11-credential-proxy-design.md`). + +**Recommendation:** ship Pattern A first. It delivers the user value with +infrastructure we already have, and exposes nothing to the public internet. +Pattern B is a worthwhile follow-up but is an infra/security project, not a +sidecar. + +## 4. Why Pattern A is cheap: every piece already exists + +A Slack bridge reuses proven seams: + +1. **A working channel-bridge template.** `modules/linear/linear-poll.mjs` + already does: detect new external messages → create `ty` task → route to + project → execute → post results back. Swap "Linear comment" for "Slack + message" and "post Linear comment" for "`chat.postMessage`". +2. **Intent classification** is solved in `ty-email/internal/classifier` + (direct Claude API call, no permission prompts). Slack messages classify the + same way. +3. **The action surface** is the `ty` CLI (what both precedents use) or the + `ty serve` HTTP API (`internal/web/server.go`: `/api/tasks`, `/tasks/{id}/input`, + `/execute`, `/logs`, `/stream` SSE, `/board`). Use the API if the bridge runs + off-box from the daemon. +4. **The push half is already aggregated.** `notifications.jsonl` (written by the + `task.blocked` / `task.completed` hooks) is a single tail-able stream of + "needs attention" events. A Slack module tails it → `chat.postMessage`. That + gives "ping me in Slack when a task blocks/finishes" almost for free, and the + GM keeps using the same file. + +Genuinely new code: a Slack **adapter** (Socket Mode or Events API + +`chat.postMessage`), thread↔task state (mirror `.linear-poll-state.json` or +`ty-email/internal/state`), and a few config flags. + +## 5. Where should it live? + +| Option | Shape | Best when | +|---|---|---| +| **`taskyou-os/modules/slack/`** (recommended) | `slack-poll.mjs` mirroring `linear-poll.mjs`; enabled via `SLACK_ENABLED=true` in `config.env`; tails `notifications.jsonl` for push | We want it to ship with the remote server, reuse the GM's notification stream, and match the existing module convention (Linear/R2/GitHub/nono are all env-flag modules bundled in the repo). | +| **`extensions/ty-slack/`** (fallback) | Go sidecar mirroring `ty-email` (adapter + classifier + bridge + state) | We want a standalone, runs-anywhere binary independent of the taskyou-os server stack, consistent with the other `extensions/` sidecars. | + +Recommended: **build it as a `taskyou-os` module.** It's the smaller diff, slots +into an established convention, and inherits `notifications.jsonl` + the GM. If a +standalone Go sidecar is preferred for distribution, `ty-email` is a clean +template — in that case, lift `ty-email`'s `bridge` and `classifier` into a +shared package both sidecars consume. ### Interaction examples - `@taskyou fix the checkout 500s and run it` → creates + executes a task, replies in-thread with the task id and a board link. -- Task hits a decision point → `ty-slack` posts *"Task #312 needs input: which - migration strategy?"* to `#taskyou`. Reply in that thread → routed to - `ty input 312 …`. +- Task hits a decision point → bridge reads `task.blocked` from + `notifications.jsonl` → posts *"Task #312 needs input: which migration + strategy?"* to the channel. Reply in-thread → routed to `ty input 312 …`. - `@taskyou what's happening with 312?` → posts recent `ty output 312`. -## 6. Security notes (same model as `ty-email`) +## 6. Security (same model the precedents use) - **Allowlist by Slack user ID**, not just channel membership — only listed - users can create/execute tasks. + users can create/execute tasks (cf. `ty-email`'s `allowed_senders`). - **Verify request authenticity** — Slack signing-secret check (Events API) or Socket Mode's authenticated socket; never act on unverified payloads. -- **No code execution from chat** — the LLM only *classifies*; the sidecar only - calls `ty` subcommands. `--dangerous` stays opt-in via config, exactly as in - `ty-email`. -- **Local secrets** — bot/app tokens resolved via `*_cmd` shell-outs, never sent - to the LLM. +- **No code execution from chat** — the LLM only *classifies*; the bridge only + calls `ty` subcommands. `--dangerous` stays opt-in via config. +- **Local secrets** — bot/app tokens via env / `*_cmd` shell-outs (like + `LINEAR_TOKEN`), never sent to the LLM. `.auth-failed`-style degradation keeps + polling alive when tokens lapse, as the Linear module already does. ## 7. Recommendation -1. **Build `ty-slack` (Pattern A)** as a sidecar in `extensions/`, refactoring - `ty-email`'s `bridge` and `classifier` into a shared package both consume. - This is a focused, low-risk follow-up — most of the surface area is proven. -2. **Defer Pattern B** (network-exposed MCP for cloud Claude) to a separate - spike; it's a hosting/auth project (pick up where PR #402 left off) and is not - required to let people drive TaskYou from Slack today. -3. The "ping me when a task is blocked/done" half can ship **immediately** as a - documented `task.blocked` / `task.completed` hook posting to a Slack incoming - webhook — independent of the full sidecar. +1. **Build Pattern A as `taskyou-os/modules/slack/`**, closely modeled on + `modules/linear/linear-poll.mjs`, enabled via `SLACK_ENABLED=true`, tailing + `notifications.jsonl` for push. (Fallback: `extensions/ty-slack` Go sidecar + modeled on `ty-email`.) +2. **Defer Pattern B** (network-exposed MCP for cloud Claude-in-Slack) to a + separate spike; it's a hosting/auth project that should build on the + credential-proxy design and where PR #402 left off. +3. The **"ping me in Slack when a task blocks/finishes"** half can ship + immediately: a `task.blocked`/`task.completed` hook (or a tiny tail of + `notifications.jsonl`) POSTing to a Slack incoming webhook — independent of + the full bridge. ## 8. Open questions for Bruno -- **Hosting:** is `ty-slack` a thing each user runs next to their daemon (like - `ty-email`), or a single shared bot for the InfluenceKit workspace? Shared → - multi-user routing + per-user allowlists become the main design work. -- **Socket Mode vs Events API:** Socket Mode needs no public URL (simplest for a - laptop/agent server). Events API is better for an always-on shared bot but - needs an HTTPS endpoint. -- **Do we also want Pattern B** (remote MCP) so the *existing* cloud Claude-in- - Slack can call `taskyou_*` tools, or is a dedicated TaskYou bot enough? +- **Home:** `taskyou-os` module (ships with the server, reuses the GM's + `notifications.jsonl`) vs. standalone `ty-email`-style sidecar (runs anywhere)? + I lean module. +- **Shared bot vs per-user:** one InfluenceKit-workspace bot (multi-user routing + + per-user allowlists become the main design work) vs. a personal bot per + operator like `ty-email`? +- **Socket Mode vs Events API:** Socket Mode needs no public URL (simplest on a + laptop/agent server); Events API suits an always-on shared bot but needs an + HTTPS endpoint. +- **Also pursue Pattern B?** Do we want the *existing* cloud Claude-in-Slack to + call `taskyou_*` tools directly (remote MCP), or is a dedicated TaskYou bot + enough?