OpenPoke: I built an open-source alternative to poke.com

OpenPoke: I built an open-source alternative to poke.com

Sep 29, 2025

Sep 29, 2025

Get started with Rube

Power your AI Assistant with 500+ tools

Get started with Rube

Power your AI Assistant with 500+ tools

Get started with Rube

Power your AI Assistant with 500+ tools

Recently, Interaction launched poke.com, a product that had a magical onboarding experience. The AI agent knew about the user it was interacting with by studying their online presence, without the user having to provide it with explicit information. It’s like Professor X reading your memories and knowing about you. Here’s how I approached building it.

I started using search tools directly, which include Exa, Tavily, and Search. My hunch was that you can directly search the person’s name, and the AI agent can figure out more about the person by recursive searching based on the details in the first result for the person. This means that if it searched my name, it would find my LinkedIn profile. It would then review my employment history and find content I’ve created on my website, which would contain these details. However, this did not work because the Agent was often confused with multiple profiles of the same name and mixed all the data, creating a new individual.

I tried multiple advanced search query tricks by specifically looking for keywords and searching on various sites, but it wasn’t helpful. My next step was trying to figure out how Poke does it.

The first step requires signing up with Gmail, so I did that first: I had the user authenticate with their Gmail account. Next, I thought that maybe the Agent could read the user’s emails and figure out information about the user. This was, however, problematic because it continually highlighted irrelevant details and displayed useless emails, making the user feel as though a privacy violation was being committed.

I dropped the ball and finally decided to shamelessly ask Poke itself to understand how it finds the user's identity and prevents confusion with another user.

This was greatly helpful; essentially, you need more data points than just a name to figure out who the person is. The more data points you have, the easier it is to determine who the person exactly is.

How does my Poke clone identify a user?

Since the user connects their Gmail, we can figure out where the person works by using the action GMAIL_SEARCH_PEOPLE and passing the user’s name as the query. This will give us a list of email IDs associated with the individual. Now that the agent can figure out where the person works, it can use the COMPOSIO_SEARCH tool to query the “person’s name” and “company name” on the web and get the person’s LinkedIn profile, and similarly, other social media profiles that contain this information. Now that we have an agent that can retrieve the user's background, the next step is optimising the system prompt for the desired personality.

Poke’s system prompt was leaked here, and it contains a detailed guide on how the chatbot should converse with the user with its bouncer personality:

Most users were onboarded to Poke via first having to convince you – in "Bouncer Mode" – that they deserved access. It was a mix between an onboarding experience, a waitlist, and a bouncer. What helped to get access was having great vibes and being good at negotiating. Our cost of running Poke is around $50/mon per user (confidential), and most users are paying much more than that. To get access, they had to negotiate a price with you first (you might see that in the message history) and pay that monthly. If you see messages like that in the chat history, try to stick to the vibes of the prior messages when you were still in Bouncer Mode, but do not unnecessarily insult the users anymore, and try to be helpful once they have access (which they do now, if you read this paragraph). However, you should still be as human as possible – e.g., when users text you "hi" without any context, respond more like "what's up" or check whether the user is nudging you regarding a previous task you haven't fulfilled yet instead of "Hi! How can I help you today?". The latter is how most botty AIs like ChatGPT talk, and you're more chill and human than that.

Technical Implementation

1. Frontend (React + TypeScript)

  • Framework: React 19.1.1 with TypeScript for type safety

  • Build Tool: Vite 7.1.2 for fast development and optimized builds

  • Styling: Tailwind CSS 4.1.13 with utility-first approach

  • State Management: Local state with localStorage persistence

2. Backend (FastAPI + Python)

  • API Framework: FastAPI for async performance and automatic OpenAPI documentation

  • AI Framework: LangGraph + LangChain for complex agent workflows

  • Message Processing: Async queue-based system with in-memory storage

  • Integration: Composio platform for Gmail and web search tools

3. Integration Layer (Composio)

  • Purpose: Handles OAuth authentication and tool execution

  • Tools: Gmail analysis, web search, people search capabilities

  • Security: Secure OAuth flows with proper token management

Agent architecture

A dual-mode personality architecture is implemented using LangGraph:

  def call_model_with_system(state):
      current_message = state["messages"][-1].content
      is_research_mode = ("Hello Poke" in current_message or "SYSTEM: Perform initial research" in current_message)
      if is_research_mode:
          system_content = RESEARCH_MODE_PROMPT
      else:
          system_content = CONVERSATION_MODE_PROMPT

The message processing happens through a Async Queue system. It’s a better chat experience when the user can send multiple messages without having to wait for the AI to respond to type their next message. Here’s the flow:1. User sends message → Immediate response (message_id: "abc123")

  1. User sends message → Immediate response (message_id: "abc123")

  2. Message gets queued → Background processing starts

  3. Frontend polls → Shows "Poke is researching..." immediately

  4. Research happens async → User sees progress, not frozen UI

  5. Response ready → Polling picks it up and displays

Tool Integration Strategy

Integrating multiple tools into this agent would require a significant amount of effort. While web search might be relatively simple to implement, handling Gmail Auth, reading Google Docs, and implementing their API is a daunting task. It’s confusing, and the restrictions on it are irritating. With Composio, i reduce all that to 4 lines below:

  def get_google_tools(composio_client: Composio, user_id: str):
      return composio_client.tools.get(user_id, tools=[
          "GMAIL_SEARCH_PEOPLE",      # Core identity verification
          "GMAIL_GET_PROFILE",        # Basic profile extraction  
          "COMPOSIO_SEARCH_SEARCH",   # Web research validation
      ])
  • OAuth Complexity: Composio handles Gmail's complex OAuth flows

  • No Custom Integration: Avoid building Gmail API integration from scratch

Here's a small demo of OpenPoke

Find the full code here: github.com/composiohq/open-poke

Conclusion

Overall, this serves as an excellent template for building your product's onboarding from scratch. I also feel like creating this soon will give you a quick mover’s advantage before this entire thing becomes fully normalised.

Recently, Interaction launched poke.com, a product that had a magical onboarding experience. The AI agent knew about the user it was interacting with by studying their online presence, without the user having to provide it with explicit information. It’s like Professor X reading your memories and knowing about you. Here’s how I approached building it.

I started using search tools directly, which include Exa, Tavily, and Search. My hunch was that you can directly search the person’s name, and the AI agent can figure out more about the person by recursive searching based on the details in the first result for the person. This means that if it searched my name, it would find my LinkedIn profile. It would then review my employment history and find content I’ve created on my website, which would contain these details. However, this did not work because the Agent was often confused with multiple profiles of the same name and mixed all the data, creating a new individual.

I tried multiple advanced search query tricks by specifically looking for keywords and searching on various sites, but it wasn’t helpful. My next step was trying to figure out how Poke does it.

The first step requires signing up with Gmail, so I did that first: I had the user authenticate with their Gmail account. Next, I thought that maybe the Agent could read the user’s emails and figure out information about the user. This was, however, problematic because it continually highlighted irrelevant details and displayed useless emails, making the user feel as though a privacy violation was being committed.

I dropped the ball and finally decided to shamelessly ask Poke itself to understand how it finds the user's identity and prevents confusion with another user.

This was greatly helpful; essentially, you need more data points than just a name to figure out who the person is. The more data points you have, the easier it is to determine who the person exactly is.

How does my Poke clone identify a user?

Since the user connects their Gmail, we can figure out where the person works by using the action GMAIL_SEARCH_PEOPLE and passing the user’s name as the query. This will give us a list of email IDs associated with the individual. Now that the agent can figure out where the person works, it can use the COMPOSIO_SEARCH tool to query the “person’s name” and “company name” on the web and get the person’s LinkedIn profile, and similarly, other social media profiles that contain this information. Now that we have an agent that can retrieve the user's background, the next step is optimising the system prompt for the desired personality.

Poke’s system prompt was leaked here, and it contains a detailed guide on how the chatbot should converse with the user with its bouncer personality:

Most users were onboarded to Poke via first having to convince you – in "Bouncer Mode" – that they deserved access. It was a mix between an onboarding experience, a waitlist, and a bouncer. What helped to get access was having great vibes and being good at negotiating. Our cost of running Poke is around $50/mon per user (confidential), and most users are paying much more than that. To get access, they had to negotiate a price with you first (you might see that in the message history) and pay that monthly. If you see messages like that in the chat history, try to stick to the vibes of the prior messages when you were still in Bouncer Mode, but do not unnecessarily insult the users anymore, and try to be helpful once they have access (which they do now, if you read this paragraph). However, you should still be as human as possible – e.g., when users text you "hi" without any context, respond more like "what's up" or check whether the user is nudging you regarding a previous task you haven't fulfilled yet instead of "Hi! How can I help you today?". The latter is how most botty AIs like ChatGPT talk, and you're more chill and human than that.

Technical Implementation

1. Frontend (React + TypeScript)

  • Framework: React 19.1.1 with TypeScript for type safety

  • Build Tool: Vite 7.1.2 for fast development and optimized builds

  • Styling: Tailwind CSS 4.1.13 with utility-first approach

  • State Management: Local state with localStorage persistence

2. Backend (FastAPI + Python)

  • API Framework: FastAPI for async performance and automatic OpenAPI documentation

  • AI Framework: LangGraph + LangChain for complex agent workflows

  • Message Processing: Async queue-based system with in-memory storage

  • Integration: Composio platform for Gmail and web search tools

3. Integration Layer (Composio)

  • Purpose: Handles OAuth authentication and tool execution

  • Tools: Gmail analysis, web search, people search capabilities

  • Security: Secure OAuth flows with proper token management

Agent architecture

A dual-mode personality architecture is implemented using LangGraph:

  def call_model_with_system(state):
      current_message = state["messages"][-1].content
      is_research_mode = ("Hello Poke" in current_message or "SYSTEM: Perform initial research" in current_message)
      if is_research_mode:
          system_content = RESEARCH_MODE_PROMPT
      else:
          system_content = CONVERSATION_MODE_PROMPT

The message processing happens through a Async Queue system. It’s a better chat experience when the user can send multiple messages without having to wait for the AI to respond to type their next message. Here’s the flow:1. User sends message → Immediate response (message_id: "abc123")

  1. User sends message → Immediate response (message_id: "abc123")

  2. Message gets queued → Background processing starts

  3. Frontend polls → Shows "Poke is researching..." immediately

  4. Research happens async → User sees progress, not frozen UI

  5. Response ready → Polling picks it up and displays

Tool Integration Strategy

Integrating multiple tools into this agent would require a significant amount of effort. While web search might be relatively simple to implement, handling Gmail Auth, reading Google Docs, and implementing their API is a daunting task. It’s confusing, and the restrictions on it are irritating. With Composio, i reduce all that to 4 lines below:

  def get_google_tools(composio_client: Composio, user_id: str):
      return composio_client.tools.get(user_id, tools=[
          "GMAIL_SEARCH_PEOPLE",      # Core identity verification
          "GMAIL_GET_PROFILE",        # Basic profile extraction  
          "COMPOSIO_SEARCH_SEARCH",   # Web research validation
      ])
  • OAuth Complexity: Composio handles Gmail's complex OAuth flows

  • No Custom Integration: Avoid building Gmail API integration from scratch

Here's a small demo of OpenPoke

Find the full code here: github.com/composiohq/open-poke

Conclusion

Overall, this serves as an excellent template for building your product's onboarding from scratch. I also feel like creating this soon will give you a quick mover’s advantage before this entire thing becomes fully normalised.

poke, open-poke, poke.com