Concrete remaining work for the current rewrite, plus open TODOs imported from
the v1 reference codebase. The active v2 tracker comes first. The rewrite plan
lives in plans/rewrite.md.
- Revisit
summarizeThreadsubagent design after there is an ephemeral Harness/Pi session path that does not create persistent sandbox rows.
- Add a bounded Slack context prelude before each Pi prompt so Gorkie starts with the local Slack situation instead of discovering basic context through tools.
- Thread mention preload: when mentioned in a Slack thread, fetch the latest thread messages before prompting Pi. Target the last 50 thread messages, sorted chronologically.
- Channel root mention preload: when mentioned in a channel root message, fetch recent top-level channel messages before prompting Pi. Target the last 20 channel messages, sorted chronologically, excluding irrelevant bot/self noise.
- Make prompt text explicit about which context was preloaded, the bounds used, and that anything outside those bounds requires Slack/Chat tools.
- Bound by message count first, then add a token/character budget if real Slack threads produce oversized prompts. Trim oldest messages first while preserving the triggering message and direct parent/root.
- Include attachments only through Chat SDK supported paths.
toAiMessagescan include images and text-like files whenfetchData()exists; log skipped unsupported attachments without failing the turn.
- Use Chat SDK APIs first: adapter
fetchMessagesfor thread replies and adapterfetchChannelMessagesfor channel context. Use Chat SDK state helpers only when pagination semantics are explicitly needed. - Convert fetched Slack messages with
toAiMessagesfromchat/aiwhen model-message shaped context is useful. PreferincludeNames: truefor multi-user thread context so Pi can distinguish speakers. - Keep the model-facing history surface small:
listThreadsfor public channel thread discovery andreadConversationHistoryfor public channel/thread reads. Add another reader only if a real workflow cannot be completed cleanly. - Fix private-channel/thread access behavior. Gorkie should not let one user use bot/tool access as global private-channel memory.
- Add per-user Slack search using the Acting User's user token, not a shared bot/admin token, so Slack filters public channels, private channels, DMs, group DMs, users, and files to exactly what that user can access.
- Store Slack user-token authorization separately from bot credentials. Token lookup must be keyed by Acting User, and tool calls must fail closed when the requesting user has not authorized the needed user scopes.
- Add user-token search tools for Slack content, files, and users with explicit result provenance. Tool results should say they came from the Acting User's Slack-visible scope, not from global bot memory.
- Keep user-token search privacy scoped. Do not persist raw private-channel or DM search results into shared agent memory, global caches, or another user's thread context.
- Add shared-channel guardrails. If a user searches private DMs or private channels from a public or multi-user thread, require a private draft/confirmation step before posting sensitive results back to the shared thread.
- Verify Slack root mention, reply-only mention, and subscribed-thread behavior.
- Fix dev channel enforcement for the
#gorkiechannel.
- Support user-token DM actions only behind per-user authorization. Starting DMs/group DMs and sending messages on behalf of the Acting User must never silently fall back to a shared user token.
- Add DM draft lifecycle task renderers: drafting, awaiting approval, edited, sent, canceled, and failed. Do not dump private message bodies into logs or task summaries.
- Evaluate Slack carousel blocks for multi-item tool outputs, especially generated images and file lists. Decide whether carousel output should replace repeated file posts after task rendering is stable.
- Add assistant-sidebar context features, such as visible channel id/context
metadata. Reference commit:
b3da0360c12bb8d1c28fd9849c18fbb747845698.
- Decide whether
apps/bot/src/lib/ai/stream/index.tsshould keep its three stream-state collections or move to a small state object. Refactor only if it clearly reduces clutter. - Live verify markdown-heavy long Slack responses split into follow-up
messages without
msg_too_long, broken tables, broken code fences, stranded list items, or dangling intro lines. - Verify task activity stays under Slack limits when reasoning blocks and tool rows are both present. Slack becomes unstable around large task counts.
- Refactor error message rendering so user-facing failures are lower-case, stage-aware, and do not confuse provider failures with Slack rendering bugs.
- Verify sandbox deletion recovery: delete or destroy a stored sandbox, send a follow-up in the same Slack thread, confirm v2 creates a fresh sandbox, re-seeds the mirrored Pi session file, and preserves conversation memory.
- Add a prompt rule for background commands: redirect output and detach, for
example
python -m http.server 8080 > /tmp/server.log 2>&1 &. - Investigate a host-owned bash override or sandbox
runwrapper that starts commands in a process group and kills the group on abort/timeout. This is the real fix for orphaned background processes that keep stdout/stderr pipes open after the shell exits.
- Handle retryable provider 524s cleanly. Observed failure:
qwen3.7-maxviaopencode-goreturned a Cloudflare 524origin_response_timeoutfromdashscope-us.aliyuncs.comwithretryable: trueandretry_after: 120.
- Add
BYOK_ENCRYPTION_KEYto bot env validation and deployment docs. Require enough entropy for AES-256-GCM key derivation. - Add a bot-owned versioned secret encryption helper.
- Add tests for the encryption helper: round-trip, tamper failure, wrong-key failure, malformed ciphertext, and no plaintext in thrown errors.
- Add
user_model_credentialsDrizzle schema and queries keyed by(user_id, provider). Store encrypted key, base URL metadata, provider slug, selected model id, key preview, validation status, validation message, last-used timestamp, and audit timestamps. - Keep raw BYOK secrets out of
packages/dbquery logs and return types unless a bot-owned decrypting service explicitly asks for the encrypted payload. - Define a single exported provider discriminant union and provider adapter
map in
packages/aifor Pi attempts: OpenRouter-compatible, opencode-go, and any direct provider added later. - Replace static
chatAttemptscall sites with per-Acting-User attempt resolution: BYOK attempts first, service attempts only when no BYOK exists or explicit service fallback is enabled. - Update turn execution, compaction, attempt selection, and attempt logging so provider/model selection is per turn and logs never include raw env or key material.
- Make
generateImagepolicy explicit in code/UI: service image provider only unless an image-capable BYOK provider is configured. - Add App Home Model Keys UI: add/rotate/delete credential, provider input, model id input, optional base URL, status display, and masked key preview only.
- Ensure Slack modal
private_metadata, view state re-renders, prompt hints, Pi session files, E2B env, task renderers, and logs never contain raw API keys. - Validate credentials on save or first use, store safe validation status, and surface invalid-key/auth/quota errors only to the Acting User where Slack allows.
- Decide service fallback UX: default off for BYOK failures, with explicit opt-in if users may spend the shared service key after their key fails.
- Add tests for provider-to-
customEnvmapping, BYOK-first fallback order, service fallback disabled, invalid-key handling, App Home modal parsing, and ownership checks. - Live smoke: save a key, run a Slack turn, run compaction, rotate the key, delete the key, trigger an invalid-key turn, and verify two users in one thread use separate credentials without leaking provider/key details.
- Investigate why Gorkie sometimes does not switch models properly.
- Verify Langfuse receives AI SDK spans using
@ai-sdk/otelplusLangfuseSpanProcessor. Current note: it does not.
- Add tests or harnessed smoke coverage for thread mention with 50-message cap, channel mention with 20-message cap, DM follow-up, failed history fetch, and attachment-skipping behavior.
- Live verify in Slack that Gorkie can answer a thread-context question from
the preload and can still call
readConversationHistoryfor older or broader context.
- Native MCP support and skill support.
- Native steering support exposing queued user messages or
submitUserMessagecleanly. - Refactored Pi provider selection that is not ENV-prefix and model-id-order dependent.
-
ai-retrysupport at the Harness/Pi boundary so custom retry logic can be deleted. - Native Langfuse/OTel support deep enough for Harness/Pi model, tool, and session internals.
- Official AI SDK E2B provider support with the resume/session-file hooks Gorkie needs.
- Pi-level retry parity with the old implementation so transient provider failures can retry inside Pi before Gorkie's outer attempt fallback runs.
Imported from /workspaces/worktrees/gorkie-slack/reference/TODO.md. These are
not automatically v2 requirements, but they capture bugs and product gaps found
in the old implementation.
- Add a configurable output cap for chat and sandbox model calls so provider
fallback requests do not reserve unaffordable default output budgets. The v1
trace showed HackClub returning Cloudflare 504 HTML, then OpenRouter rejecting
fallback with a 402 because it reserved up to
65_536output tokens. - Add multi-provider retry for the Pi sandbox agent so coding-agent failures can fall back to alternative providers instead of ending the task.
- Evaluate whether the primary chat model should move from Gemini Flash to a smaller GPT-5 family model. Document cost, latency, context, and quality tradeoffs before changing defaults.
- Remove the local
ai-retrypatch when upstream supports AI SDK 7 without local declaration changes. Until then, keep AI SDK packages on the same v7 canary line, keepai-retrypinned, and smoke-test provider fallback after provider or AI SDK bumps.
- Show manually denied tools in the thinking/task panel after approval resume. Denied approvals need synthetic pre-tasks in the new response stream.
- Improve MCP tool task display. Show the normalized MCP tool name in the
title, such as
Using Fathom: list_meetings, plus concise clamped input and output previews. - Lock down connection-defining MCP server fields after creation. URL, transport, and auth type should require deleting and re-adding the server.
- Add scheduled MCP OAuth token refresh before expiry and record refresh failures without breaking unrelated MCP servers.
- Add MCP tool discovery before full OAuth so users can preview available tools in the Slack setup flow.
- When setting an entire MCP tool group, apply the change to the whole group, not only the currently visible pagination page. Search results can stay scoped to the visible results.
- If a terminal tool fires without visible reasoning, show the terminal task
directly, such as
Replied,Skipping, orLeft channel, instead of a generic thinking task. - Investigate intermittent missing thinking/reasoning in Slack task streams. Verify reasoning lifecycle events appear before tool calls and remain visible after terminal tasks.
- Prevent Slack task cards from overflowing block limits. Start a continuation task card when the current card approaches Slack limits.
- Make Slack search errors non-fatal so a search failure does not mark an otherwise successful task as failed.
- Fix pinned-item detection for Slack search results. Confirm whether
user-specific pinning requires
pins.list,conversations.info, or another Slack API path. - After sandbox upload tools run, inject the uploaded file list into the model-visible response context so the agent knows what was uploaded.
- Investigate why
agent-browser --snapshot /path/to/file.pngdoes not save files where the sandbox agent expects them. Determine whether it writes relative to the command CWD, daemon CWD, or a temp directory. - Add
agentmailto the E2B sandbox template or document it as a first-run install for theagent-browserskill.
- Clean up message pipeline utilities from the old Slack stack:
message-context.ts,triggers.ts,conversations.ts, andcontext.ts. Remove duplicatedusers.infopatterns and tighten stale types if any of that code is reintroduced. - Continue reducing schema and type clutter. Move reusable types into clear type owners, keep Slack actions/views feature-owned, and avoid one-shot helpers.
- Consider whether more package extraction is worth it, especially observability and sandbox logic, if those areas become shared by bot and server code.
- Build out
packages/kvbefore any feature uses it. Add typed key builders and query helpers, and decide whether serverless paths need Upstash instead of a persistent Redis connection.
- Add an opt-in checkpoint flow for larger agent tasks. Commits must stay scoped to the current task and avoid unrelated dirty worktree changes.
- If a planning thread exceeds roughly 50 messages, start a new planning block to avoid context degradation.