RunAgent simplifies serverless deployment of your AI agents. With a powerful CLI, multi-language SDK support, built-in agent invocation & streaming suppprt.
Running AI agents in production means wiring together model inference, session state, tool execution, and a serving layer. Most teams build this glue themselves, then bolt on deployment. RunAgent packages that glue into a CLI and multi-language SDK so agent code stays portable across local development and serverless hosting.
What This Does
RunAgent is a deployment and runtime layer for AI agents. The Python core (runagent/) provides a CLI (run, serve, init commands) and an SDK with a REST client (runagent/sdk/rest_client.py), local server (runagent/sdk/server/local_server.py), and database layer (runagent/sdk/db.py). It supports LangChain, Agno, and other frameworks via a generic adapter (runagent/sdk/server/framework/generic).
The repo is a portfolio of 8 self-contained projects, not a single codebase. Beyond the Python core, there are SDKs in Rust (runagent-rust/), Go (runagent-go/), TypeScript (runagent-ts/), Dart (runagent-dart/), and C# (runagent-csharp/), plus 196 files of examples covering stock agents, trip planners, book writers, and RAG systems.
How It Is Wired
Execution starts at one of three CLI entry points: run (runagent/cli/commands/run.py:62, reaches 112 functions), serve (serve.py:55, reaches 35), or init (init.py:48, reaches 76). The run command is the busiest—it reaches 112 functions and is called from 3 places. A typical path is run -> run_stream -> llm.stream, a network call to the model, with query (38 callers) and get_session (36 callers) as the most depended-on functions.
The wiring is hub-and-spoke around three modules: runagent/__init__.py (45 modules import it), runagent/cli/branding.py (13 importers), and runagent/constants.py (13 importers). runagent/sdk/db.py is the database owner (48 functions, reads/writes DB, makes network calls); runagent/sdk/rest_client.py is the HTTP owner (42 functions, 17 importers, participates in an import cycle with config.py).
File-by-file: db.py handles sessions and initialization, rest_client.py handles HTTP requests and error responses, sdk.py handles configuration and validation, local_server.py handles the FastAPI app and dependency installation. The cycle between rest_client.py and config.py makes changes to either ripple unpredictably.
How To Use It
Setup: pnpm is the package manager; Docker and GitHub Actions are configured. Python dependencies are pinned in pyproject.toml.
Running: The CLI is the primary interface—runagent run executes an agent, runagent serve starts a local server. Examples show direct invocation: examples/Stockagent/main.py and examples/book_writer/backend/app.py are working entry points.
Configuration: Agent config lives in runagent.config.json files (see chatbot_example/langgraph_sqlite/runagent.config.json). The SDK reads user config via get_user_config.
Real-World Use
A stock-analysis agent (examples/Stockagent/) demonstrates the pattern: agent.py defines the agent with model calls, main.py wires it to the SDK, and the CLI deploys it. The SDK's create_agent_with_tools -> create path shows how tool-calling agents get registered and invoked.
Code Health & Issues
Static analysis found 131 findings (33 high, 98 medium). Leading issues:
Critical - Pinned black@25.9.0 carries CVE-2026-31900 (critical, network-reachable). Upgrade and commit the lockfile.
High - GitHub Actions pinned to tags (softprops/action-gh-release@v1), not commit SHAs. Tag moves = token compromise risk.
High - 8 more pinned dependencies with published advisories (requests, pyasn1, protobuf, urllib3).
High - No lockfile beside pyproject.toml; CI has 40 test files but no test command in workflows.
High - Deep nesting (max depth 8) in db.py, rest_client.py, config.py; oversized files (db.py at 1468 lines).
Medium - Broad exception handling (23 instances), no Dependabot, no dependency vulnerability scan, 4 blobs over 5MB including a 23.6MB Dart snapshot.
The Bottom Line
RunAgent is a legitimate multi-language agent deployment platform with real SDKs, working examples, and CI. The critical dependency advisory and unpinned CI actions need immediate attention before production use. For teams standardizing agent deployment across Python, Go, and Rust, it's worth evaluating; the example portfolio is substantial enough to validate the approach.
What the analyser found
Deployment readiness
7/7
✓Container image
✓CI pipeline
✓Lockfile committed
✓Test suite
✓README
✓License
✓No committed secrets
Composition
682 files
Python189
JSON71
Markdown47
Rust38
Go27
YAML25
ReactFlaskExpressTailwindDockerLangChainCUDA
Architecture
Top-level areas of the codebase, sized by module count. Arrows show how many imports cross from one area into another.
Ranked by severity × confidence × production reach. Reach is the honest discriminator across a collection that is mostly other people's code: the same finding matters more in something that ships.
critical1
high4
medium7
low2
Upgrade the pinned dependency carrying a critical advisorycritical3 occurrences
black@25.9.0 CVE-2026-31900 (critical) +2 more
The manifest pins the exact version the advisory covers, so this is not a warning about drift: the vulnerable code is what installs, and a critical rating means it is reachable over the network without credentials or user interaction.
Fix: Upgrade to the fixed version named in the advisory, then commit the lockfile.
Pin third-party GitHub Actions to a commit SHAhigh2 occurrences
A tag can be moved, so the action running with your token and secrets is whatever its owner last pushed; this is how tj-actions/changed-files leaked secrets from thousands of repos.
Fix: Replace each @vN with the 40-character commit SHA, keep # vN as a comment, and let Dependabot bump the SHAs.
Upgrade the pinned dependency carrying a published advisoryhigh31 occurrences
The pinned version is the one that installs, so a published advisory against it describes this deployment rather than a hypothetical one, and the advisory is also a public description of how to exploit it.
Fix: Upgrade to the fixed version named in the advisory, then commit the lockfile.
Commit a lockfile beside the manifesthigh
pyproject.toml
manifest with no lockfile in scope
An unlocked range means the artifact you tested and the artifact you ship can contain different transitive code, so a malicious patch release reaches production with no diff.
Fix: Run the package manager once and commit the generated lockfile.
Make CI invoke the test suite it hashigh40 occurrences
.github/workflows
40 test files, no test command in the 4 workflows read
A green check that never executed an assertion is worse than no check, because reviewers trust it.
Fix: Add a test step to the existing workflow rather than a new workflow.
Declare least-privilege permissions for GITHUB_TOKENmedium
.github/workflows/python-release.yml
1 workflow(s) declare no permissions, 1 of them reference secrets
With no declaration the token inherits the repository default, so any injected step can push commits or mint releases from inside your own CI.
Fix: Add permissions: contents: read at the top of the workflow and widen per job only where needed.
Enable Dependabot or Renovatemedium
32 manifest(s), no update bot configured
Without a bot a published advisory sits unpatched until someone audits by hand, which across 1,322 repositories means never.
Fix: Commit .github/dependabot.yml covering the repo ecosystems plus github-actions.
Install from the lockfile in CImedium
.github/workflows
npm install with a committed package-lock.json
A fresh resolution in CI means the tested dependency set is not the locked one, so the failure only appears after merge.
Fix: Use npm ci, yarn install --immutable, or pnpm install --frozen-lockfile.
Gate pull requests on a dependency vulnerability scanmedium
.github/workflows
no dependency scan in CI
This is the one gate that would catch a known-vulnerable package before it reaches a build, and no repository in the sample had it.
Fix: Add dependency-review-action on pull_request, or osv-scanner on push and a schedule.
Move large binaries to Git LFS or out of the repositorymedium4 occurrences
4 blobs over 5MB: test.dart-3.10.0.snapshot 23.6MB, basic 11.4MB, runagent_ecosystem_final2.svg 5.3MB
One repository here carries twenty blobs over 5MB including a 10.9MB spreadsheet, so every clone and every CI checkout pays for data nobody diffs.
Fix: Track those extensions with LFS, or move datasets to object storage and fetch them in a setup step.
Set persist-credentials: false on checkoutmedium
.github/workflows/create-release.yml
checkout keeps the token, then dependencies are installed
The token stays in .git/config for every later step, so a malicious postinstall script reads a pushable credential without one ever being passed to it.
Fix: Add with: persist-credentials: false, and pass an explicit token only to the step that pushes.
Expand the test suite; it cannot cover this codebasemedium9 occurrences
9 test files against 208 source files (ratio 0.043)
A reviewer reads "has tests" and assumes a safety net that covers two files out of eighty-five, which is how untested paths ship behind a green badge.
Fix: Add tests for the highest fan-in modules first.
2 further finding(s) are listed in the full report.
Checked deterministically against the repository tree and a bounded set of its files: committed credentials, unpinned actions and base images, missing lockfiles and update bots, workflows that discard failures, published advisories against the declared dependencies, runtime configuration, licensing and notebook reproducibility. No language model is involved in this section.