SevenTnewS

The Security Architecture of AI Coding Agents

Hugging Face's Slack bot queries production data. The LLM never sees the keys

Hugging Face runs an internal Slack coding agent, Moon Bot, that can query production databases and open PRs. Its security design keeps credentials out of the model's reach via Okta tiers, sandboxed bash, and local reverse proxies that inject keys server-side.

Emmanuel Fabrice Omgbwa Yasse AI-assisted

2026-08-04 · 5 min read

Hugging Face's Slack bot queries production data. The LLM never sees the keys

Most teams do not publish the details of how their coding agent touches production data. Hugging Face did. Moon Bot, an internal Slack bot, queries production Elasticsearch and MongoDB, opens GitHub pull requests, and remembers what it worked on last week. The model behind it never holds the credentials that make any of that possible.

Moon Bot sounds trivial until you try to build it. Agents that work in demos often stall in production, the planning trap that keeps showing up in operator reports. It runs on the open-source Pi coding agent SDK in a Kubernetes pod, and every Slack thread gets its own independent agent session with full tool-call history. The post names Kimi K2 and Claude as possible backends. Support staff ask about user-facing behavior without a terminal; engineers check whether a feature exists or something is a bug. Asking "how many Pro users signed up last month?" becomes one line in Slack instead of hunting through the dashboards.

Sessions in object storage

The persistence layer is the quiet standout. The bot keeps three files in a private HuggingFace Bucket named huggingface/moon-bot-memory. Each thread appends its full message history, tool calls included, as a JSONL file. A thread-map file connects Slack timestamps to session files, and a memory log holds the last 200 interactions across all threads, searchable by the model. Because sessions live in object storage, a deploy or a crash costs nothing: the bot downloads the right file on demand and resumes where it left off, even days later. That puts the working memory outside the model, a plain fix for the long-task memory failures identified in agent research.

Every reply links back to the bucket: Moon Bot uploads the markdown response and session JSONL, then appends buttons to the message. HuggingFace renders the file as a native agent trace viewer, so every interaction is auditable from the thread itself. That is the audit trail most enterprise agent deployments still lack.

Credentials the model can't touch

The security design is where the post earns its keep. Moon Bot resolves an access tier for each Slack user from their Okta group membership, matched by email, mirroring the access those groups already gate. Basic covers any HuggingFace employee: code Q&A, read-only GitHub, and shell. Elastic adds log and storage skills for people with Elasticsearch access. Privileged, for people with database access in Okta, reaches MongoDB and AWS. Guests are refused outright. Each tier maps to a separate Linux user with its own credentials, so lower tiers physically lack the secrets to reach Mongo or AWS. Resolution fails closed: if Okta can't be read, everyone drops to basic, and the bot says so on every reply. Permission boundaries that live outside the model, enforced by Linux users instead of prompts, are the same layer addressed by new research on agent permission violations.

Tool calls run under the tier's restricted user via su -l, with no access to /root/, where the real secrets live. Suspicious commands raise a Slack alert before executing, and the model has a report_injection tool to self-report prompt injection. Local reverse proxies cover the rest: the bot starts HTTP proxies at startup, each gated by a per-tier token, and injects the real API key server-side, so the sandboxed runner hits localhost:9201 and never sees it. The Plausible proxy is hard-allowlisted to a single query endpoint and carries its own token handed to every tier, so anyone can pull public traffic analytics. A compromised tool call can query what its tier allows, but it cannot exfiltrate the credentials.

Pull requests work the same way. The agent's sandboxed gh is read-only for almost everyone. Writes go through dedicated in-process tools that mint a short-lived GitHub App token, commit and push, then discard it, outside the agent's reach. Two properties fall out: any employee can ask for a draft PR without personal write access, and PR descriptions are assembled in code, not by the model, so every PR ends with a footer naming the requester and linking the Slack thread and the agent trace. A second, far less privileged pod runs the same codebase as a GitHub bot, with no Slack token and no database credentials.

Skills are the pluggable part: Markdown files injected into the system prompt that tell the model how to drive a domain. The rule is that every skill wraps a CLI tool, never a direct API call, which keeps each one testable and easy to swap. The post lists eight, covering Elasticsearch logs, MongoDB, the Hub and Spaces codebases, GitHub, AWS Athena, Xet storage, and public traffic analytics.

SkillInterfaceWhat it queries
es-cliRust CLIElasticsearch access logs
mongomongoshHub user database
githubgh + in-process PR toolsRepos, pull requests, issues
hub-codegh, grep, findHub codebase
workloadsgh, grep, findSpaces, Endpoints, Jobs codebase
athenaAWS CLI wrapperALB, WAF, CloudFront logs
sizzleDuckDB wrapperXet storage statistics
plausibleStats API wrapperPublic traffic analytics

A pattern worth copying

The post calls the pattern simple enough to replicate: a bucket or any object store, the Pi SDK, some skill files, and a Slack app in Socket Mode. The infrastructure to get started, it says, is surprisingly thin; the hardest part is writing good skills. That undersells the security scaffolding, which most teams would skip. What makes Moon Bot work is that the risk was engineered away rather than managed by policy: tiers enforced by separate Linux users, credentials injected by local proxies, write tokens minted and destroyed per PR.

Moon Bot is an internal tool, with the advantages of one: a single SSO domain, known users, one team's codebases. That narrowness is part of why it works, and it is a reminder that public benchmark scores do not survive contact with a specific private codebase: top models can hit 96% on SWE-bench Verified and barely clear 23% on private enterprise code. The transferable lesson is the pattern: make every action auditable, and keep every credential out of reach of the model that uses it.

Get the tech essentials in 3 minutes every morning

One email, every weekday, with what actually matters in AI and tech.