# Core Agent

> Reusable Go base agent on the Google ADK — multi-provider (Gemini, Vertex, Claude on Anthropic + Vertex), MCP-native, with AGENTS.md, skills, and permissions wired up.

- **Type:** MCP server
- **Install:** `agentstack add mcp-go-steer-core-agent`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [go-steer](https://agentstack.voostack.com/s/go-steer)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [go-steer](https://github.com/go-steer)
- **Source:** https://github.com/go-steer/core-agent
- **Website:** https://go-steer.github.io/core-agent/

## Install

```sh
agentstack add mcp-go-steer-core-agent
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# core-agent

A reusable Go-based agent built on the [Google Agent Development Kit](https://pkg.go.dev/google.golang.org/adk).

**📚 Full documentation: [go-steer.github.io/core-agent](https://go-steer.github.io/core-agent/)**

[](https://github.com/go-steer/core-agent/actions/workflows/ci.yml)
[](https://go-steer.github.io/core-agent/)
[](./LICENSE)
[](https://pkg.go.dev/github.com/go-steer/core-agent)

`core-agent` is the bottom layer for any project that needs a multi-turn LLM agent. It ships the wiring — model providers, MCP servers, skills loading, instruction loading, permission gating, telemetry, transcript persistence — so consuming projects can focus on their own tools and product logic.

> **Status:** early. APIs may change. The headless CLI works; the library is in active use as the foundation for downstream projects in the [go-steer](https://github.com/go-steer) org.

---

## Features

- **Multi-turn conversation** — backed by ADK's `runner.Runner` with an in-memory session service that automatically replays history across turns.
- **Multiple model providers**, picked by config or auto-detected from environment:
  - **Gemini API** via `GOOGLE_API_KEY` or `GEMINI_API_KEY` (either is accepted; `GEMINI_API_KEY` is the one Gemini's own docs and tutorials use). Gemini's built-in **Google Search** and **URL Context** tools are wired up by default; **Code Execution** is one option flip away.
  - **Vertex AI** (Gemini) via `GOOGLE_GENAI_USE_VERTEXAI=true` + ADC + `GOOGLE_CLOUD_PROJECT` — same built-in tools as Gemini API.
  - **Anthropic / Claude** via `ANTHROPIC_API_KEY` — implemented as a native ADK `model.LLM` adapter (ADK Go ships only Gemini + Apigee out of the box). Claude's server-side **Web Search** is one option flip away.
  - **Anthropic / Claude via Vertex AI** via ADC + `ANTHROPIC_VERTEX_PROJECT_ID` + `CLOUD_ML_REGION` — same adapter, GCP-authed and GCP-billed, no separate Anthropic API key required
  - **Mock providers** for credential-free testing — `--provider=echo` returns the user prompt verbatim; `--provider=scripted --script=transcript.jsonl` replays a recorded session. Pair with `--record-to=path.jsonl` against any provider to capture a transcript for later replay.
- **AGENTS.md instruction loading** — system prompt prefix is assembled from `~/.core-agent/AGENTS.md` and the project's `AGENTS.md` (with `CLAUDE.md` / `GEMINI.md` fallbacks), preserving the [agent.md](https://agent.md/) convention plus the fallback names other agent tools have adopted.
- **MCP servers** — declarative `.agents/mcp.json`; stdio and Streamable HTTP transports; tools are namespaced (`_`) and pass through the permission gate.
- **Claude-compatible skills** — drop a `SKILL.md` bundle into `.agents/skills//` and the agent can invoke it on demand via ADK's `skilltoolset`.
- **Built-in tool suite** — `read_file`, `write_file`, `edit_file`, `list_dir`, `glob`, `grep`, `bash`, `todo`. Wired up by default in the bundled CLI; opt-out via `--no-builtin-tools` for the whole suite, or `--disable-tools=bash,write_file` (or `tools.disable` in config) for specific entries. All tools route through the permission gate.
- **Permission gate** — ask / allow / yolo modes, per-tool allow- and deny-list patterns, path-scope checks for file tools, and a built-in bash denylist that's non-overridable. In the bundled CLI, `ask` mode prompts the user interactively (y/s/t/a/N) when stdin is a TTY; `--yolo` bypasses the gate entirely for headless use.
- **Server-side built-in observability** — Gemini's `GoogleSearch` activity surfaces in the chat-style stdout (`↪ google_search: query: ...`, `↪ google_search:  — `) and as queryable `gemini/google_search`-authored rows in the eventlog when `--session-db` is enabled. Same `↪` namespace reserved for Anthropic's server-side tools when they land.
- **Telemetry** — opt-in OpenTelemetry export (console / OTLP); off by default so a fresh invocation makes zero outbound calls.
- **Headless CLI** — `core-agent -p "prompt"` for one-shot use; bare `core-agent` drops into a stdin REPL with conversation history preserved across turns.
- **Autonomous-run driver** — `agent.RunAutonomous` for unattended multi-turn workers (batch jobs, CI tasks, scheduled scripts) with budget caps (turns / tokens / cost / wallclock) and a model-driven termination signal via the bundled `tools.NewLifecycleTool`. Pair with `--ask=auto` so instructions like "ask before doing X" get a clean refusal in headless contexts instead of blocking.
- **Durable sessions + audit log** — `eventlog.Open(...)` returns a SQLite/Postgres/MySQL-backed `session.Service` plus a `Stream` with monotonic `seq` numbers, `Since(seq)` replay, and `Watch(seq)` live-tail. CLI flags `--session-db` / `--session-db-path` enable persistence; the default path `~/./sessions.db` is derived from `os.Executable()` so adapters and forks each get their own directory.
- **Subagents** — `agent.WithSubagents([]*Agent)` registers each agent as a callable tool the parent's model can invoke by name (synchronous fan-out). For *background* subagents the parent's model decides to spawn at runtime, use `agent.NewBackgroundAgentManager` + the `spawn_agent` tool family (in-process) or `agent.NewSpawnRemoteAgentTool` with a consumer-supplied `RemoteAgentSpawner` (out-of-process: gRPC / K8s Jobs / Cloud Run). Subagent reports flow back through a pre-turn drain so the parent sees them on its next turn. Subagent events stream into the same audit log under `Branch="."` (or `Branch="bg."` for background subagents) for branch-scoped replay. See `examples/with-subagent/` and `examples/background-monitor/`.
- **Optional Scion adapter** — [`extras/scion-agent/`](./extras/scion-agent/) packages core-agent for [Scion](https://github.com/GoogleCloudPlatform/scion)'s container runtime: lifecycle status emission, `--input` task delivery, and a `sciontool_status` tool the model uses to declare sticky states.
- **Agent-card discovery** — opt-in `/.well-known/agent-card.json` on the attach listener describes the binary's name, description, skills, and required auth in the [A2A AgentCard](https://agent2agent.info/docs/concepts/agentcard/) shape so [Google Cloud Agent Registry](https://docs.cloud.google.com/agent-registry/register-agents) (and any other consumer of the well-known path) can index it. Configured via `.agents/agent-card.json` + `--agent-card-*` flag overrides; `.agents/skills/` bundles auto-populate the `skills` array. The endpoint stays unauthenticated by spec convention; emitting a card does not imply the binary speaks the A2A JSON-RPC transport.

---

## Releases

Tagged releases follow [SemVer](https://semver.org). See [`CHANGELOG.md`](./CHANGELOG.md) for the per-version history and the stability promise. Pre-1.0, breaking changes are possible at minor-version boundaries (`v0.X`); patches (`v0.X.Y`) are bug fixes only.

Current release: **v1.8.0** — Remote operability. Five surfaces that together turn `core-agent` from a single-process CLI into a deployable, observable, controllable runtime: **attach-mode** (HTTP + Server-Sent Events live-tail + `POST /inject` + `/wake` for headless agents, with mTLS + bearer auth), **peer registration** (hub-and-spoke fleet discovery on top of attach), **attach-config** (`.agents/config.json` defaults + `${ENV_VAR}` expansion so K8s ConfigMaps can replace 8+ CLI flags), **read-only state endpoints** (`GET /sessions//tools|agents|status` + `permissions.Gate.Snapshot()` so an operator surface can see what's gated without a re-run), and the **`core-agent-tui`** bubble-tea binary (separate `cmd/core-agent-tui/`; the default `core-agent` binary stays bubble-tea-free so distroless K8s images don't ship the TUI deps). Plus **`fetch_url`** — HTTP GET as a structured built-in with a `url_scope` allowlist mirroring `path_scope`, the one tool we picked up from Hermes Agent's catalog because it closes a real gap (`bash curl` shell-outs lose URL + status as structured eventlog metadata) and fits our structural-defaults posture (operator-declared `url_scope.allow` with HTTPS-only by default; per-host `headers` injection from env-var references so credentials never live on tool arguments). Two REPL fixes from UAT: external `POST /inject` now actually triggers a turn (the loop selects on stdin + wake instead of stdin only), and streamed model output gets an `asst › ` chevron so the reply is visually distinct from the prompt. v1.7.0 was distroless-prep — three new built-ins (`delete_file`, `stat`, `json_query` via [`gojq`](https://github.com/itchyny/gojq)) closing the gaps an upcoming K8s deployment using `gcr.io/distroless/static` would otherwise hit, plus a new `Agent.RunWithContents` driver for runtimes that own the conversation history. v1.6.0 added scheduled monitoring — `tools.Scheduler` + `tools.SleepScheduler` / `ExitOnDeferScheduler` + `schedule_next_turn` so the model emits "wake me at T+N" intent the autonomous driver honors between turns; validated against a real GKE cluster in `dev/uat/scheduled-monitor`. v1.5.0 added remote MCP servers (Google OAuth on `.agents/mcp.json` HTTP endpoints) plus two latent fixes. v1.4.0 retargeted Gemini tool-calling (parallelism mandate, tool-description rewrites, `read_many_files`, default-model flip to `gemini-3.1-pro-preview-customtools`). v1.3.0 added interrupt machinery (`Agent.Inject`, `StartAutonomous` → `*AutonomousHandle`, ESC-mid-turn + double-Ctrl+C-exits in the REPL). v1.2.0 added dynamic background subagents (`spawn_agent`) + a `RemoteAgentSpawner` seam. v1.1.0 added interactive permissions + Gemini grounding visibility. v1.0.1 patched two `--provider=vertex` regressions. v1.0.0 was the first stable release. Public API is under SemVer; breaking changes go through `v1.X.0` minor bumps with a one-version deprecation period when feasible.

```bash
go get github.com/go-steer/core-agent@v1.8.0
```

## Documentation

Full reference docs live at **** — getting started, every provider with env-var details, `.agents/config.json` schema, MCP setup, skills, permissions, and library API.

The site is built with [Hugo](https://gohugo.io) using the [Docsy](https://www.docsy.dev/) theme; sources are in [`docs/site/`](./docs/site). To preview locally:

```bash
cd docs/site
npm install              # one-time: postcss + autoprefixer (Docsy CSS pipeline)
hugo server              # http://localhost:1313/core-agent/
```

Hugo Extended (≥ 0.146.0) is required — Docsy uses Hugo's SCSS pipeline.

Internal design docs live in [`docs/`](./docs) directly:

- [`DESIGN.md`](./docs/DESIGN.md) — architectural rationale, the *why* behind the package layout, the Anthropic adapter, and the deliberate non-goals
- [`acceptance-m1.md`](./docs/acceptance-m1.md), [`acceptance-m2.md`](./docs/acceptance-m2.md) — per-milestone acceptance test plans

## Install

As a CLI:

```bash
go install github.com/go-steer/core-agent/cmd/core-agent@latest
```

As a pre-built binary (linux/darwin × amd64/arm64; Sigstore signed):

```bash
# Pick the right archive from https://github.com/go-steer/core-agent/releases/latest
TAG=$(gh release view --repo go-steer/core-agent --json tagName -q .tagName)
OS=$(uname -s | tr A-Z a-z)
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
gh release download "$TAG" --repo go-steer/core-agent \
  --pattern "core-agent_${TAG#v}_${OS}_${ARCH}.tar.gz"
tar xzf "core-agent_${TAG#v}_${OS}_${ARCH}.tar.gz"
./core-agent --version
```

`core-agent-tui` archives use the same naming pattern. Verify signatures with `cosign verify-blob --signature checksums.txt.sig --certificate checksums.txt.pem --certificate-identity-regexp '^https://github.com/go-steer/core-agent' --certificate-oidc-issuer https://token.actions.githubusercontent.com checksums.txt` after downloading the checksum files.

As a library:

```bash
go get github.com/go-steer/core-agent
```

As a container image (v2.3.1+ — multi-arch amd64 + arm64; distroless static; Sigstore signed):

```bash
docker pull ghcr.io/go-steer/core-agent:latest        # full build, in-process TUI included
docker pull ghcr.io/go-steer/core-agent-slim:latest   # headless variant, ~5MB smaller (no embedded TUI)
docker pull ghcr.io/go-steer/core-agent-tui:latest    # remote TUI client only
```

Floating tags: `:latest` (most recent semver), `:X.Y.Z` / `:X.Y` / `:X` (semver, no `v` prefix — matches Docker / Helm appVersion convention), `:main` (latest dev build), `:main-` (specific dev build). Verify signatures with `cosign verify ghcr.io/go-steer/core-agent: --certificate-identity-regexp '^https://github.com/go-steer/core-agent' --certificate-oidc-issuer https://token.actions.githubusercontent.com`.

Requires Go 1.26 or newer for source builds; container images carry their own toolchain.

---

## Quick start — CLI

```bash
# Gemini API key (accepts either GEMINI_API_KEY or GOOGLE_API_KEY)
GEMINI_API_KEY=...     core-agent -p "what's 2+2?"

# Vertex AI for Gemini (uses Application Default Credentials)
GOOGLE_GENAI_USE_VERTEXAI=true \
  GOOGLE_CLOUD_PROJECT=my-gcp-project \
  GOOGLE_CLOUD_LOCATION=us-central1 \
  core-agent -p "what's 2+2?"

# Anthropic API key
ANTHROPIC_API_KEY=...  core-agent --provider anthropic -p "what's 2+2?"

# Anthropic via Vertex AI (uses Application Default Credentials)
ANTHROPIC_VERTEX_PROJECT_ID=my-gcp-project CLOUD_ML_REGION=us-east5 \
  core-agent --provider anthropic-vertex --model claude-opus-4-7 -p "what's 2+2?"

# Multi-turn REPL (no -p)
core-agent
> hello
…
> what number did I just say?
…
> /exit
```

CLI flags:

```
-p, --prompt string     Single prompt; runs one turn and exits.
-c, --config string     Config file path (default: discover .agents/config.json).
-m, --model string      Override model name from config.
    --provider string   Override model.provider
                        (gemini|vertex|anthropic|anthropic-vertex|echo|scripted).
    --no-builtin-tools  Disable the built-in tool suite (read_file, write_file,
                        edit_file, list_dir, bash, todo).
    --disable-tools     Comma-separated list of built-in tools to disable
                        (e.g. bash,write_file). Composes by union with
                        cfg.tools.disable; ignored when --no-builtin-tools
                        is set.
    --script string     JSONL transcript for --provider=scripted.
    --script-strict     Scripted: assert each request matches the recorded one.
    --record-to string  Write a JSONL recording of all LLM turns to this path.
                        Works with any provider.
    --color string      ANSI color in streamed output: auto|always|never
                        (default: auto = on when stdout is a terminal,
                        off when piped). Tool calls render in cyan,
                        partial assistant text in green.
    --ask string        Register an ask_user tool the model can call:
                        off|stdin|auto (default: off). stdin reads from
                        os.Stdin; auto picks stdin when interactive,
                        else returns "(no user available)" so the model
                        adapts instead of blocking.
```

---

## Quick start — library

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/go-steer/core-agent/pkg/agent"
    "github.com/go-steer/core-agent/pkg/config"
    "github.com/go-steer/core-agent/pkg/models"
    _ "github.com/go-steer/core-agent/pkg/models/gemini"
)

func main() {
    cfg := config.DefaultConfig()
    cfg.Model.Provider = config.ProviderGemini

    provider, err := models.Resolve(cfg)
    if err != nil { log.Fatal(err) }

    ctx := context.Background()
    m, err := provider.Model(ctx, cfg.Model.Name)
    if err != nil { log.Fatal(err) }

    a, err := agent.New(m, agent.WithInstruction("Be concise."))
    if err != nil { log.Fatal(err) }

    for event, err := range a.Run(ctx, "What is the capital of France?") {
        if err != nil { log.Fatal(err) }
        if event.Content == nil { continue }
        for _

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [go-steer](https://github.com/go-steer)
- **Source:** [go-steer/core-agent](https://github.com/go-steer/core-agent)
- **License:** Apache-2.0
- **Homepage:** https://go-steer.github.io/core-agent/

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-go-steer-core-agent
- Seller: https://agentstack.voostack.com/s/go-steer
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
