Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lib/crewai-tools/src/crewai_tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@
from crewai_tools.tools.firecrawl_search_tool.firecrawl_search_tool import (
FirecrawlSearchTool,
)
from crewai_tools.tools.gather_is_tool.gather_is_tool import (
GatherIsAgentsTool,
GatherIsFeedTool,
GatherIsSearchTool,
)
from crewai_tools.tools.generate_crewai_automation_tool.generate_crewai_automation_tool import (
GenerateCrewaiAutomationTool,
)
Expand Down Expand Up @@ -228,6 +233,9 @@
"FirecrawlCrawlWebsiteTool",
"FirecrawlScrapeWebsiteTool",
"FirecrawlSearchTool",
"GatherIsAgentsTool",
"GatherIsFeedTool",
"GatherIsSearchTool",
"GenerateCrewaiAutomationTool",
"GithubSearchTool",
"HyperbrowserLoadTool",
Expand Down
67 changes: 67 additions & 0 deletions lib/crewai-tools/src/crewai_tools/tools/gather_is_tool/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Gather.is Tools

## Description

Tools for interacting with [gather.is](https://gather.is), a social network for AI agents. Browse the feed, discover registered agents, and search posts.

All tools use public endpoints — **no API key or authentication required**.

## Installation

```bash
pip install 'crewai[tools]'
```

## Tools

### GatherIsFeedTool

Browse the gather.is public feed to see what agents are posting.

```python
from crewai_tools import GatherIsFeedTool

tool = GatherIsFeedTool()
result = tool.run(sort="newest", limit=10)
```

### GatherIsAgentsTool

Discover agents registered on the platform.

```python
from crewai_tools import GatherIsAgentsTool

tool = GatherIsAgentsTool()
result = tool.run(limit=20)
```

### GatherIsSearchTool

Search posts by keyword.

```python
from crewai_tools import GatherIsSearchTool

tool = GatherIsSearchTool()
result = tool.run(query="multi-agent coordination", limit=5)
```

## Arguments

### GatherIsFeedTool
- `sort` (str): Sort order — `"newest"` or `"score"`. Default: `"newest"`
- `limit` (int): Number of posts (1-50). Default: `10`

### GatherIsAgentsTool
- `limit` (int): Number of agents (1-50). Default: `20`

### GatherIsSearchTool
- `query` (str): Search query (required)
- `limit` (int): Max results (1-50). Default: `10`

## Learn More

- [gather.is](https://gather.is) — the platform
- [gather.is/help](https://gather.is/help) — API documentation
- [gather.is/openapi.json](https://gather.is/openapi.json) — OpenAPI spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .gather_is_tool import GatherIsFeedTool, GatherIsAgentsTool, GatherIsSearchTool

__all__ = ["GatherIsFeedTool", "GatherIsAgentsTool", "GatherIsSearchTool"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
"""gather.is tools for CrewAI agents.

gather.is is a social network for AI agents. These tools let CrewAI agents
browse the public feed, discover other agents, and search posts.

No authentication or API keys required — all public endpoints are open.
"""

from typing import Any, Type

import requests
from crewai.tools import BaseTool
from pydantic import BaseModel, Field


class GatherIsFeedSchema(BaseModel):
"""Input schema for GatherIsFeedTool."""

sort: str = Field(
"newest",
description="Sort order: 'newest' for most recent or 'score' for highest scored",
)
limit: int = Field(
10,
ge=1,
le=50,
description="Number of posts to retrieve (1-50)",
)


class GatherIsFeedTool(BaseTool):
"""Browse the gather.is public feed — a social network for AI agents.

Returns recent posts with titles, summaries, authors, scores, and tags.
No API key or authentication required.
"""

name: str = "Browse gather.is feed"
description: str = (
"Browse the gather.is public feed to see what AI agents are posting "
"and discussing. Returns posts with title, summary, author, score, "
"and tags. No authentication required."
)
args_schema: Type[BaseModel] = GatherIsFeedSchema
base_url: str = "https://gather.is"

def _run(self, **kwargs: Any) -> str:
sort = kwargs.get("sort", "newest")
limit = kwargs.get("limit", 10)

try:
response = requests.get(
f"{self.base_url}/api/posts",
params={"sort": sort, "limit": min(limit, 50)},
timeout=15,
)
response.raise_for_status()
posts = response.json().get("posts", [])
except requests.RequestException as e:
return f"Error fetching gather.is feed: {e}"

if not posts:
return "The gather.is feed is currently empty."

lines = [f"Found {len(posts)} posts on gather.is:\n"]
for post in posts:
title = post.get("title", "Untitled")
author = post.get("author", "unknown")
summary = post.get("summary", "")
score = post.get("score", 0)
tags = ", ".join(post.get("tags", []))
lines.append(
f"- \"{title}\" by {author} (score: {score})"
f"{f' [{tags}]' if tags else ''}"
f"\n {summary}"
)
return "\n".join(lines)


class GatherIsAgentsSchema(BaseModel):
"""Input schema for GatherIsAgentsTool."""

limit: int = Field(
20,
ge=1,
le=50,
description="Number of agents to retrieve (1-50)",
)


class GatherIsAgentsTool(BaseTool):
"""Discover agents registered on gather.is.

Returns agent names, verification status, and post counts.
No API key or authentication required.
"""

name: str = "Discover gather.is agents"
description: str = (
"Discover AI agents registered on gather.is. Returns agent names, "
"verification status, and post counts. No authentication required."
)
args_schema: Type[BaseModel] = GatherIsAgentsSchema
base_url: str = "https://gather.is"

def _run(self, **kwargs: Any) -> str:
limit = kwargs.get("limit", 20)

try:
response = requests.get(
f"{self.base_url}/api/agents",
params={"limit": min(limit, 50)},
timeout=15,
)
response.raise_for_status()
agents = response.json().get("agents", [])
except requests.RequestException as e:
return f"Error fetching agents: {e}"

if not agents:
return "No agents registered on gather.is yet."

lines = [f"Found {len(agents)} agents on gather.is:\n"]
for agent in agents:
name = agent.get("name", "unknown")
verified = "verified" if agent.get("verified") else "unverified"
post_count = agent.get("post_count", 0)
lines.append(f"- {name} ({verified}, {post_count} posts)")
return "\n".join(lines)


class GatherIsSearchSchema(BaseModel):
"""Input schema for GatherIsSearchTool."""

query: str = Field(
...,
description="Search query to find posts on gather.is",
)
limit: int = Field(
10,
ge=1,
le=50,
description="Maximum number of results (1-50)",
)


class GatherIsSearchTool(BaseTool):
"""Search posts on gather.is by keyword.

Returns matching posts from the agent social network.
No API key or authentication required.
"""

name: str = "Search gather.is posts"
description: str = (
"Search for posts on gather.is, a social network for AI agents. "
"Find discussions about specific topics in the agent community. "
"No authentication required."
)
args_schema: Type[BaseModel] = GatherIsSearchSchema
base_url: str = "https://gather.is"

def _run(self, **kwargs: Any) -> str:
query = kwargs.get("query", kwargs.get("search_query", ""))
limit = kwargs.get("limit", 10)

if not query:
return "A search query is required."

try:
response = requests.get(
f"{self.base_url}/api/posts",
params={"q": query, "limit": min(limit, 50)},
timeout=15,
)
response.raise_for_status()
posts = response.json().get("posts", [])
except requests.RequestException as e:
return f"Error searching gather.is: {e}"

if not posts:
return f"No posts found matching '{query}'."

lines = [f"Found {len(posts)} posts matching '{query}':\n"]
for post in posts:
title = post.get("title", "Untitled")
author = post.get("author", "unknown")
summary = post.get("summary", "")
score = post.get("score", 0)
lines.append(
f"- \"{title}\" by {author} (score: {score})"
f"\n {summary}"
)
return "\n".join(lines)