DEV Community

Cover image for Build your own Google Antigravity agent in Slack
Denis Valášek
Denis Valášek

Posted on

Build your own Google Antigravity agent in Slack

In the world of project management and team collaboration, the holy grail is reducing friction. Previously, we looked at how to make Trello cards talk back The Power of Gemini inside Trello and how to bring Gemini into your workspace Gemini in your Slack workspace.

But what if you wanted a highly intelligent, stateful team assistant living directly in Slack that could answer complex, open-ended questions about your Trello boards? Questions like:

  • "Which cards did I edit last week?"
  • "Show me all comments made across my active boards in the last 7 days."
  • "What is the current status of the card XYZ?"

Answering these questions requires more than simple semantic search; it requires a tool that can dynamically write retrieval scripts, parse complex multi-board JSON payloads, filter dates, and compile elegant reports.

In this article, we'll explore how to build exactly that using Google’s Antigravity Managed Agent (the "Agy" agent), integrated into Slack's native Agent View, utilizing a secure, stateful, and sandboxed remote execution environment.


🚀 Prerequisites

Before starting, make sure you have:


🔒 Security & Environment Controls: The Agy Sandbox Philosophy

At the heart of this setup is Google's Antigravity (Agy) Managed Agent. Instead of running in a transient stateless environment, the Agy agent operates inside a persistent, secure, and remote Linux sandbox equipped with standard execution engines (Python, Node.js, bash, etc.).

When a Slack user asks a question, the Agy agent dynamically writes a script, runs it in its isolated sandbox, inspects the Trello API output, self-corrects if any errors occur, and presents a formatted response.

In this article, we focus on Trello, but the same principles can be applied to any other system with good APIs or (MCPs)[https://ai.google.dev/gemini-api/docs/antigravity-agent#mcp-servers], which the Agy agent also supports.

However, giving a remote code-executing sandbox direct access to your third-party API keys is a major security risk. If a malicious prompt convinced the LLM to print its environment variables, your Trello tokens would be leaked.

🛡️ Zero-Exposure Credentials with Egress Proxy Transformations

To solve this, we implement a Zero-Exposure Security Architecture. We do not pass Trello API credentials in the system instructions, nor do we set them as environment variables inside the sandbox.

Instead, we leverage the Google GenAI Egress Proxy Header Transformations (environment.network.allowlist.transform). We configure the remote sandbox network stack so that any HTTP request sent to api.trello.com automatically has the OAuth Authorization headers injected by Google's secure egress proxy:

// Construct the environment config with egress transformations
const environmentConfig = {
  type: "remote",
  environment_id: existingEnvId, // Thread persistence
  network: {
    allowlist: [
      {
        domain: "api.trello.com",
        transform: {
          // The credentials are automatically injected securely at the proxy level!
          Authorization: `OAuth oauth_consumer_key="${trelloApiKey}", oauth_token="${trelloToken}"`,
        },
      },
      {
        domain: "*", // Allow general internet for resolving code dependencies
      },
    ],
  },
};
Enter fullscreen mode Exit fullscreen mode

Because of this proxy-level transformation, the Agy agent can write scripts that request Trello data without ever seeing, containing, or storing the actual API Key or Token:

import urllib.request
# Safe script written by Agy agent: Notice there are no credentials in the code!
url = "https://api.trello.com/1/boards/my_board_id/actions?filter=updateCard,commentCard"
req = urllib.request.Request(url)
# The proxy automatically handles the authorization header injection securely!
response = urllib.request.urlopen(req)
Enter fullscreen mode Exit fullscreen mode

If the agent tries to print its variables, files, or scripts, your credentials remain 100% invisible. Furthermore, we enforce strict read-only system instructions, guaranteeing the sandbox never executes destructive POST, PUT, or DELETE requests.


🔄 Stateful Conversations: Mapping Thread TS to Environment ID

In standard chatbot integrations, every reply is completely stateless. If you say "What is the status of card XYZ?" followed by "Assign me to it," the bot has no memory of what card you were talking about.

Since the Agy agent utilizes persistent remote sandboxes, we can map the unique Slack thread timestamp (thread_ts) to the Google sandbox environment_id.

// Retrieve the persistent Google environment ID for this Slack thread
const existingEnvId = await environmentStore.get(threadTs);

const interaction = await ai.interactions.create({
  agent: "trello-slack-agent",
  input: userInput,
  environment: buildEnvironmentConfig(existingEnvId),
});

// Save the new environment ID associated with this thread
await environmentStore.set(threadTs, interaction.environment_id);
Enter fullscreen mode Exit fullscreen mode

On consecutive messages in the same thread, the Agy agent wakes up in the exact same remote sandbox, preserving files, variables, and execution context from previous messages!


🤖 Fluid UX with Slack's Native Agent View

To make the agent feel like a native, premium Slack experience, we utilize Slack's dedicated agent_view. This lets us pin suggested welcome prompts directly inside the agent’s Message tab, guiding the user on how to interact:

// Listening for App Home opened to dynamically publish suggested prompts
app.event("app_home_opened", async ({ event, client }) => {
  if (event.tab === "messages") {
    await client.apiCall("assistant.threads.setSuggestedPrompts", {
      channel_id: event.channel,
      title: "Ask about your Trello boards:",
      prompts: [
        {
          title: "Recent Edits",
          message: "Which cards did I edit last week?",
        },
        {
          title: "Card Status",
          message: "What is the status of the card xyz?",
        },
        {
          title: "Comments History",
          message: "Show me my comments over the last week.",
        },
      ],
    });
  }
});
Enter fullscreen mode Exit fullscreen mode

We also integrate the native Slack typing indicators using assistant.threads.setStatus so the team knows exactly when Agy is provisioning a sandbox or executing a script.


📈 Solving Slack's 4,000 Character Barrier

When the Agy agent compiles extensive card histories or comments from the past week, the output can easily exceed several thousand characters. Under standard Slack integrations, this triggers the dreaded msg_too_long error, which caps text blocks at 4,000 characters.

To handle this elegantly, our backend monitors the response length dynamically. If the Agy response is under 3,500 characters, it's posted directly into the chat. If it exceeds that, the backend dynamically compiles the full response and uploads it as an elegant, native Markdown (.md) file directly inside the Slack thread:

const SLACK_CHAR_LIMIT = 3500;

if (outputText.length <= SLACK_CHAR_LIMIT) {
  await client.chat.update({
    channel,
    ts: loadingMsgTs!,
    text: outputText,
  });
} else {
  // Graceful fallback for long outputs
  await client.chat.update({
    channel,
    ts: loadingMsgTs!,
    text: ":file_folder: *The response is quite long, so I have uploaded it as a Markdown file below!*",
  });

  // Upload markdown file inside the thread
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  await client.files.uploadV2({
    channel_id: channel,
    filename: "antigravity-response.md",
    content: outputText,
    thread_ts,
    initial_comment: ":memo: *Full response from Antigravity:*",
    request_file_info: false,
  } as any);
}
Enter fullscreen mode Exit fullscreen mode

This ensures the Slack thread stays clean and compact, while still delivering comprehensive and rich reports without ever failing due to platform constraints.


🛠️ Infrastructure and Deployment

The backend is built with:

  • Hono.js: An ultra-fast, lightweight web framework to serve endpoints and health checks.
  • Slack Bolt SDK: Utilizing Socket Mode to communicate with Slack in real-time, eliminating the need to expose public HTTP webhook endpoints.
  • pnpm workspaces: Strict dependency control, ESM-first configuration, and comprehensive Vitest unit tests.

To run the agent locally:

  1. Copy .env.example to .env and fill in your integration credentials.
  2. Install dependencies and start the watcher:
   pnpm install
   pnpm run dev
Enter fullscreen mode Exit fullscreen mode

To deploy to production, a multi-stage Dockerfile is included in the project, packaging the agent into a secure, minimal container optimized for performance.


💡 Conclusion

By using Google's Antigravity Managed Agent with Slack's Agent View, we’ve built more than a simple Q&A bot. We've created an isolated, stateful, and secure script-execution pipeline that can dynamically parse and interpret complex Trello boards.

Thanks to egress proxy header transformations, we achieve absolute credential security, and by integrating smart Markdown file uploading, we overcome native message size limits seamlessly.

Check out the full source code and deploy your own state-of-the-art Slack Agent!

Next steps

There are many ways to improve the current implemenetation if you want to extend this yourself, full code setup is on GitHub and you don't need any paid plans.

Here are some ideas:

  • Writing custom Skills for different teams
  • Create MCP server to safe-guard writes through the API
  • More personification by pulling users context
  • Have different input and modalities other than Slack

Top comments (0)