Skip to content

feat(reborn): add Slack personal (user-token) tool#5177

Open
sergeiest wants to merge 1 commit into
mainfrom
feat/slack-user-tool-reborn
Open

feat(reborn): add Slack personal (user-token) tool#5177
sergeiest wants to merge 1 commit into
mainfrom
feat/slack-user-tool-reborn

Conversation

@sergeiest

Copy link
Copy Markdown

What

Ports the bot-token-free Slack personal tool (originally #4941, old architecture) to the Reborn extension architecture. It lets IronClaw act as the user via a Slack user token (xoxp-) — read full message history, DMs, group DMs, and search — things a bot token fundamentally cannot do.

Distinct from the bot Slack channel: it has its own credential, so the personal token never collides with slack_bot_token.

Capabilities

slack_user.{search_messages, list_conversations, get_conversation_history, get_user_info, send_message}

How it's built (mirrors the google-sheets / github WASM tools)

  • WASM tool source tools-src/slack_user/sandboxed-tool WIT, context-dispatched (action derived from capability_id, action-less per-capability params).
  • reborn.extension_manifest.v2 at crates/ironclaw_first_party_extensions/assets/slack_user/ (manifest + embedded wasm/ + per-capability input schemas + prompt docs).
  • Registration in ironclaw_reborn_composition: available_extensions.rs catalog + factory.rs first-party trust policy. Gated behind slack-v2-host-beta, like the bot Slack extension.

Credential model (two deliberate choices)

  • product_auth_account with default ManualToken setup (mirrors the github PAT tool), not secret_handle. The WebUI manual-token auth-gate save path keys on a provider; a provider-less secret_handle credential makes the gate fail with "Could not save the token."
  • provider slack_personal (not slack) so the user-token credential is a separate account from the bot Slack extension (id slack) and its IRONCLAW_REBORN_SLACK_BOT_TOKEN config — the personal tool never picks up the bot token. Bearer-injected to slack.com; no OAuth provider required.

Auth / setup

Manual token: create a private Slack app, add User Token Scopes (search:read, channels:history, groups:history, im:history, mpim:history, *:read, users:read, optional chat:write), install, and paste the resulting xoxp- user token into the extension's auth gate.

Testing

  • cargo component build --target wasm32-wasip2 → clean component; tool clippy/fmt clean.
  • RUSTFLAGS=-D warnings cargo build -p ironclaw_reborn_cli --features webui-v2-beta,slack-v2-host-beta → clean.
  • ironclaw_reborn_composition catalog + trust-policy tests pass (manifest parses, registers, digest pinned).
  • Verified end to end against a live serve: the auth gate saves the xoxp- token and search_messages authorizes as the user.

🤖 Generated with Claude Code

Port the bot-token-free Slack personal tool (originally nearai/ironclaw
PR #4941) to the Reborn extension architecture. Lets IronClaw act as the
user via a Slack user token (xoxp-) to read full message history, DMs,
group DMs, and search — things a bot token cannot do.

- WASM tool source at tools-src/slack_user/ (sandboxed-tool WIT), with
  context-dispatched capabilities: search_messages, list_conversations,
  get_conversation_history, get_user_info, send_message.
- reborn.extension_manifest.v2 manifest at
  crates/ironclaw_first_party_extensions/assets/slack_user/ with a
  manual-token credential: product_auth_account provider "slack_personal"
  with the default ManualToken setup (mirrors the github PAT tool),
  bearer-injected to slack.com — no OAuth provider required.
  Two deliberate choices:
  * product_auth_account (not secret_handle) so the WebUI manual-token
    auth gate can save the pasted token: the gate/save path keys on a
    provider, and a provider-less secret_handle credential made the gate
    fail with "Could not save the token".
  * provider "slack_personal" (not "slack") so the user-token credential
    is a separate account from the bot Slack extension (id "slack") and
    its IRONCLAW_REBORN_SLACK_BOT_TOKEN config — the personal tool never
    picks up the bot token.
  Per-capability input schemas + prompts mirror the google-sheets tool.
- Registered in ironclaw_reborn_composition (available_extensions catalog
  + factory first-party trust policy), gated behind slack-v2-host-beta.

Builds clean with RUSTFLAGS=-D warnings; composition catalog/trust tests
pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@railway-app

railway-app Bot commented Jun 24, 2026

Copy link
Copy Markdown

This PR was not deployed automatically as @sergeiest does not have access to the Railway project.

In order to get automatic PR deploys, please add @sergeiest to your workspace on Railway.

@github-actions github-actions Bot added scope: docs Documentation size: XL 500+ changed lines risk: low Changes to docs, tests, or low-risk modules contributor: new First-time contributor labels Jun 24, 2026
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added a new Slack personal-user integration that can search messages, list conversations, read conversation history, look up user info, and send messages.
    • Expanded support for Slack user-token actions with structured inputs and outputs for each operation.
    • Enabled the new Slack personal-user tool in supported builds.
  • Documentation

    • Added user-facing setup and usage guidance for the Slack personal-user tool and its required Slack permissions.

Walkthrough

Adds a new slack_user first-party extension that exposes five Slack personal user-token operations (search messages, list conversations, get conversation history, get user info, send message) as a WASM component. Includes the Rust tool crate, JSON schemas, prompt docs, extension manifest, and host-side registration under slack-v2-host-beta.

Changes

Slack Personal (User-Token) Extension

Layer / File(s) Summary
Data types, action enum, and JSON schemas
tools-src/slack_user/src/types.rs, crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/*.json
ToolContext, SlackUserAction (serde-tagged, JsonSchema-derived), and all response structs are defined. Five input schemas and one raw output schema are introduced with additionalProperties: false and draft-07 metadata.
Slack API HTTP layer
tools-src/slack_user/src/api.rs
slack_api_call wrapper (percent-encode helper, host::http_request, status+ok validation) and five public functions: search_messages, list_conversations, get_conversation_history, get_user_info, send_message.
WASM guest entry point and action dispatcher
tools-src/slack_user/src/lib.rs, tools-src/slack_user/Cargo.toml
SlackUserTool exports execute/schema/description. action_from_context maps capability_id to action tags; params_with_action injects the tag before enum deserialization. Cargo.toml configures cdylib + release optimizations.
Extension manifest, prompts, and capabilities
crates/ironclaw_first_party_extensions/assets/slack_user/manifest.toml, crates/.../prompts/slack_user/*.md, tools-src/slack_user/slack_user-tool.capabilities.json, tools-src/slack_user/README.md
Manifest declares five capabilities with effects (external_write only on send_message), slack_user_token Bearer credential, schema/prompt refs, and egress. Prompt docs and tool capabilities JSON are added.
Host-side package registration and trust policy
crates/ironclaw_reborn_composition/src/available_extensions.rs, crates/ironclaw_reborn_composition/src/factory.rs
Embeds manifest and WASM bytes, constructs and registers slack_user_package() in AvailableExtensionCatalog, and pushes a first-party AdminEntry (using gsuite_allowed_effects()) into builtin_first_party_trust_policy — all under #[cfg(feature = "slack-v2-host-beta")].

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • nearai/ironclaw#4779: Adds the bot-token slack first-party extension using the identical factory.rs pattern (slack_manifest_digest + AdminEntry::for_local_manifest under slack-v2-host-beta) that this PR mirrors for slack_user.

Suggested reviewers

  • serrrfirat
  • think-in-universe

Poem

A user token sneaks through the gate,
xoxp- bearer, no bot to imitate.
Five capabilities, effects declared,
external_write only when sending is dared. 🔐
WASM compiled, the manifest sealed —
Slack as yourself, identity revealed.

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the feature, but it does not follow the required template sections or include several mandatory fields. Rewrite the PR description to match the template, adding Summary, Change Type, Linked Issue, Validation, Security Impact, trust-boundary checklist, Database Impact, Blast Radius, Rollback Plan, Review Follow-Through, and Review track.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is Conventional Commits-style and accurately summarizes the new Slack personal user-token tool.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new Slack personal (user-token) WASM tool (slack_user) to allow IronClaw to act as a user in Slack, implementing capabilities such as searching messages, listing conversations, reading history, getting user info, and sending messages. The feedback suggests refactoring the reuse of gsuite_allowed_effects() for the Slack package to avoid domain boundary violations, stripping query parameters from the logged endpoint in api.rs to prevent leaking sensitive data, and clamping the limit parameter in list_conversations and get_conversation_history for defensive input validation.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

"/system/extensions/slack_user/manifest.toml".to_string(),
Some(slack_user_manifest_digest()),
HostTrustAssignment::first_party(),
gsuite_allowed_effects(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Reusing gsuite_allowed_effects() for the slack_user first-party package is a domain boundary violation, as Slack is not part of the GSuite domain. While using a centralized helper is preferred to maintain drift-resistance and avoid duplicating domain knowledge locally, in a future refactoring we should rename this helper to a more generic name (e.g., wasm_tool_allowed_effects()) or split it to maintain proper domain boundaries.

References
  1. Prefer routing through centralized helper functions that define domain boundaries or strip transient fields (e.g., credential_owner_scope()) to maintain drift-resistance and avoid duplicating domain knowledge locally, even if it introduces minor performance overhead (like cloning) on non-hot paths.

Comment on lines +47 to +50
host::log(
host::LogLevel::Debug,
&format!("Slack API: {} {}", method, endpoint),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Logging the full endpoint string can leak sensitive user-supplied query parameters (such as search queries or message contents) into the debug logs. To ensure only sanitized identifiers are logged and prevent sensitive data exposure, we should strip the query parameters from the endpoint before logging.

Suggested change
host::log(
host::LogLevel::Debug,
&format!("Slack API: {} {}", method, endpoint),
);
let log_endpoint = endpoint.split('?').next().unwrap_or(endpoint);
host::log(
host::LogLevel::Debug,
&format!("Slack API: {} {}", method, log_endpoint),
);
References
  1. Do not use warn! or info! logging in REPL/TUI-reachable code as they can corrupt the REPL/TUI. Use debug! logging instead, and ensure only sanitized identifiers are logged.

Comment on lines +118 to +123
pub fn list_conversations(types: &str, limit: u32) -> Result<ListConversationsResult, String> {
let url = format!(
"conversations.list?types={}&limit={}&exclude_archived=true",
url_encode(types),
limit
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To enforce defensive programming and ensure robust handling of invalid inputs, we should clamp the limit parameter to a valid range (e.g., 1 to 1000) before constructing the API URL. This prevents potential API errors or unexpected behavior if schema validation is bypassed.

Suggested change
pub fn list_conversations(types: &str, limit: u32) -> Result<ListConversationsResult, String> {
let url = format!(
"conversations.list?types={}&limit={}&exclude_archived=true",
url_encode(types),
limit
);
pub fn list_conversations(types: &str, limit: u32) -> Result<ListConversationsResult, String> {
let limit = limit.clamp(1, 1000);
let url = format!(
"conversations.list?types={}&limit={}&exclude_archived=true",
url_encode(types),
limit
);
References
  1. When implementing methods that poll for batches of data (e.g., poll_inputs), ensure that the caller-provided limit is clamped or bounded by a predefined maximum value (e.g., MAX_HOST_INPUT_POLL_LIMIT) before being passed to underlying host queues or services. This prevents performance degradation from excessively large batch requests.

Comment on lines +151 to +161
pub fn get_conversation_history(
channel: &str,
limit: u32,
latest: Option<&str>,
oldest: Option<&str>,
) -> Result<ConversationHistoryResult, String> {
let mut url = format!(
"conversations.history?channel={}&limit={}",
url_encode(channel),
limit
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To enforce defensive programming and ensure robust handling of invalid inputs, we should clamp the limit parameter to a valid range (e.g., 1 to 1000) before constructing the API URL. This prevents potential API errors or unexpected behavior if schema validation is bypassed.

pub fn get_conversation_history(
    channel: &str,
    limit: u32,
    latest: Option<&str>,
    oldest: Option<&str>,
) -> Result<ConversationHistoryResult, String> {
    let limit = limit.clamp(1, 1000);
    let mut url = format!(
        "conversations.history?channel={}&limit={}",
        url_encode(channel),
        limit
    );
References
  1. When implementing methods that poll for batches of data (e.g., poll_inputs), ensure that the caller-provided limit is clamped or bounded by a predefined maximum value (e.g., MAX_HOST_INPUT_POLL_LIMIT) before being passed to underlying host queues or services. This prevents performance degradation from excessively large batch requests.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/raw_output.v1.json`:
- Around line 5-6: The slack_user raw_output schema is too permissive because
the top-level object allows any properties, so validation cannot detect
malformed tool outputs. Update the raw_output.v1.json contract to use explicit
shapes instead of a free-form object by defining strict per-operation schemas
and combining them with a discriminated oneOf union, and ensure the Slack user
output schema rejects unexpected or partial payloads.

In `@crates/ironclaw_reborn_composition/src/factory.rs`:
- Line 3042: The Slack package is using the wrong ceiling helper,
`gsuite_allowed_effects()`, which ties Slack permissions to an unrelated G-Suite
helper; update the Slack manifest wiring in `factory.rs` to use a dedicated
`slack_user_allowed_effects()` instead. Add or reuse the Slack-specific helper
so it matches the manifest’s declared Slack effects, preserving current
capabilities like `external_write` without depending on future changes to the
G-Suite helper.

In `@tools-src/slack_user/src/types.rs`:
- Around line 31-33: The remaining free-form CSV field in
list_conversations.types should be replaced with a typed, validated value to
match the schema-bounded approach already used for search_messages.sort. Update
the types definition in slack_user/src/types.rs by introducing an enum or
newtype list for the allowed conversation kinds, then wire it through the
list_conversations input model so deserialization validates the values instead
of accepting arbitrary strings. Keep the JSON schema in
slack_user/list_conversations.input.v1.json aligned with the Rust type so both
sides enforce the same allowed set.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4fabd8e5-38ea-48a0-a4a2-a625dbf87393

📥 Commits

Reviewing files that changed from the base of the PR and between e754655 and 3da3e3e.

⛔ Files ignored due to path filters (1)
  • crates/ironclaw_first_party_extensions/assets/slack_user/wasm/slack_user_tool.wasm is excluded by !**/*.wasm, !**/*.wasm
📒 Files selected for processing (20)
  • crates/ironclaw_first_party_extensions/assets/slack_user/manifest.toml
  • crates/ironclaw_first_party_extensions/assets/slack_user/prompts/slack_user/get_conversation_history.md
  • crates/ironclaw_first_party_extensions/assets/slack_user/prompts/slack_user/get_user_info.md
  • crates/ironclaw_first_party_extensions/assets/slack_user/prompts/slack_user/list_conversations.md
  • crates/ironclaw_first_party_extensions/assets/slack_user/prompts/slack_user/search_messages.md
  • crates/ironclaw_first_party_extensions/assets/slack_user/prompts/slack_user/send_message.md
  • crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/get_conversation_history.input.v1.json
  • crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/get_user_info.input.v1.json
  • crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/list_conversations.input.v1.json
  • crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/raw_output.v1.json
  • crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/search_messages.input.v1.json
  • crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/send_message.input.v1.json
  • crates/ironclaw_reborn_composition/src/available_extensions.rs
  • crates/ironclaw_reborn_composition/src/factory.rs
  • tools-src/slack_user/Cargo.toml
  • tools-src/slack_user/README.md
  • tools-src/slack_user/slack_user-tool.capabilities.json
  • tools-src/slack_user/src/api.rs
  • tools-src/slack_user/src/lib.rs
  • tools-src/slack_user/src/types.rs

Comment on lines +5 to +6
"type": "object",
"additionalProperties": true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

raw_output is effectively untyped, so output validation cannot catch shape regressions.

Line 5–6 accepts any object. Since this schema is registered by the host as the tool output contract, malformed/partial payloads can pass validation and break downstream assumptions. Please tighten this to explicit output shapes (e.g., per-operation schemas or a strict oneOf union).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/raw_output.v1.json`
around lines 5 - 6, The slack_user raw_output schema is too permissive because
the top-level object allows any properties, so validation cannot detect
malformed tool outputs. Update the raw_output.v1.json contract to use explicit
shapes instead of a free-form object by defining strict per-operation schemas
and combining them with a discriminated oneOf union, and ensure the Slack user
output schema rejects unexpected or partial payloads.

"/system/extensions/slack_user/manifest.toml".to_string(),
Some(slack_user_manifest_digest()),
HostTrustAssignment::first_party(),
gsuite_allowed_effects(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

gsuite_allowed_effects() is the wrong-named ceiling for a Slack package.

It currently happens to cover the union of slack_user effects (incl. external_write for send_message), so it's functionally correct today. But coupling Slack's effect ceiling to a G-Suite helper is fragile: any future narrowing of gsuite_allowed_effects() would silently drop a Slack capability. Prefer a dedicated slack_user_allowed_effects() matching the manifest's declared effects.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/ironclaw_reborn_composition/src/factory.rs` at line 3042, The Slack
package is using the wrong ceiling helper, `gsuite_allowed_effects()`, which
ties Slack permissions to an unrelated G-Suite helper; update the Slack manifest
wiring in `factory.rs` to use a dedicated `slack_user_allowed_effects()`
instead. Add or reuse the Slack-specific helper so it matches the manifest’s
declared Slack effects, preserving current capabilities like `external_write`
without depending on future changes to the G-Suite helper.

Comment on lines +31 to +33
/// Sort by `score` (relevance, default) or `timestamp` (recency).
#[serde(default)]
sort: Option<String>,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all stringly-typed bounded fields and their downstream usage before migration.
rg -n --type rust 'sort:\s*Option<String>|types:\s*String' tools-src/slack_user/src/types.rs
rg -n --type rust 'SearchMessages|ListConversations|as_deref\(' tools-src/slack_user/src/lib.rs tools-src/slack_user/src/api.rs
rg -n '"sort"|"types"' crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/*.json

Repository: nearai/ironclaw

Length of output: 1866


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' tools-src/slack_user/src/types.rs | cat -n
printf '\n--- schema: search_messages ---\n'
sed -n '1,120p' crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/search_messages.input.v1.json | cat -n
printf '\n--- schema: list_conversations ---\n'
sed -n '1,120p' crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/list_conversations.input.v1.json | cat -n

Repository: nearai/ironclaw

Length of output: 9208


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' tools-src/slack_user/src/types.rs | cat -n
printf '\n--- schema: search_messages ---\n'
sed -n '1,120p' crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/search_messages.input.v1.json | cat -n
printf '\n--- schema: list_conversations ---\n'
sed -n '1,120p' crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/list_conversations.input.v1.json | cat -n

Repository: nearai/ironclaw

Length of output: 9208


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' tools-src/slack_user/src/types.rs | cat -n
printf '\n--- schema: search_messages ---\n'
sed -n '1,120p' crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/search_messages.input.v1.json | cat -n
printf '\n--- schema: list_conversations ---\n'
sed -n '1,120p' crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/list_conversations.input.v1.json | cat -n

Repository: nearai/ironclaw

Length of output: 9208


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' tools-src/slack_user/src/types.rs | cat -n
printf '\n--- schema: search_messages ---\n'
sed -n '1,120p' crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/search_messages.input.v1.json | cat -n
printf '\n--- schema: list_conversations ---\n'
sed -n '1,120p' crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/list_conversations.input.v1.json | cat -n

Repository: nearai/ironclaw

Length of output: 9208


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' tools-src/slack_user/src/api.rs | cat -n

Repository: nearai/ironclaw

Length of output: 8885


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' tools-src/slack_user/src/api.rs | cat -n

Repository: nearai/ironclaw

Length of output: 8885


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' tools-src/slack_user/src/api.rs | cat -n

Repository: nearai/ironclaw

Length of output: 8885


Make list_conversations.types a typed value

search_messages.sort is already schema-bounded; the remaining gap is tools-src/slack_user/src/types.rs:39-42 / crates/ironclaw_first_party_extensions/assets/slack_user/schemas/slack_user/list_conversations.input.v1.json:7, where types is still a free-form CSV string. Model the allowed conversation kinds as a validated enum/newtype list and keep the schema aligned.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools-src/slack_user/src/types.rs` around lines 31 - 33, The remaining
free-form CSV field in list_conversations.types should be replaced with a typed,
validated value to match the schema-bounded approach already used for
search_messages.sort. Update the types definition in slack_user/src/types.rs by
introducing an enum or newtype list for the allowed conversation kinds, then
wire it through the list_conversations input model so deserialization validates
the values instead of accepting arbitrary strings. Keep the JSON schema in
slack_user/list_conversations.input.v1.json aligned with the Rust type so both
sides enforce the same allowed set.

Source: Coding guidelines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: new First-time contributor risk: low Changes to docs, tests, or low-risk modules scope: docs Documentation size: XL 500+ changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant