scion-agent

command
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 16, 2026 License: Apache-2.0 Imports: 32 Imported by: 0

README

scion-agent

scion-agent runs core-agent inside Scion's container runtime. It is the Go counterpart of Scion's Python adk_scion_agent example, built on top of core-agent's library.

What it does

  • Loads the same .agents/config.json, MCP servers, skills, instruction file, and built-in tools as core-agent.
  • Adds a sciontool_status ADK tool so the model can declare sticky lifecycle states (ask_user, blocked, task_completed, limits_exceeded) to Scion's hub.
  • Emits transient activity (thinking, executing, working) to $HOME/agent-info.json automatically on each agent / tool boundary, so Scion's UI can render live progress.
  • Accepts --input <task> to seed the first turn (Scion's harness appends this when starting an agent with a task) and then reads stdin for follow-up messages — scion message <agent> delivers them via tmux send-keys.

Outside a Scion container the lifecycle hooks degrade to no-ops, so the same binary is usable for local development with no Scion runtime.

Build

The Dockerfile builds the Go binary from source and lays it on top of scion-base (which provides sciontool, tmux, and the scion user):

# From the core-agent repo root, not from this directory.
docker build \
  --build-arg BASE_IMAGE=scion-base:latest \
  -t scion-core-agent \
  -f extras/scion-agent/Dockerfile .

You need a scion-base image available locally. Build it from the Scion repo first if you don't have one.

Register the template with Scion

Copy the templates/scion/ tree into Scion's templates directory (or point Scion at it directly):

templates/scion/
├── scion-agent.yaml                       # schema_version, default harness
├── agents.md                              # system instruction shipped with the agent
└── harness-configs/scion/config.yaml      # image, user, task_flag, args

Then create an agent in Scion that uses this template — see the Scion docs for the exact CLI.

Run locally (no container)

go build -o /tmp/scion-agent ./extras/scion-agent
GOOGLE_API_KEY=… /tmp/scion-agent --input "list the files in this directory"

You'll see:

  • Agent text streamed to stdout.
  • → <tool> / ← <tool> lines on stderr as tools are called.
  • $HOME/agent-info.json ticking through thinking / executing / working (tail it in another shell to watch live).
  • After the model calls sciontool_status("task_completed", "..."), the file flips to completed (sticky).

When sciontool is not on PATH, the sticky-state subprocess calls become quiet no-ops — the rest of the agent still runs normally.

Design notes

Lifecycle hooks live in the adapter, not in core-agent

The adapter's streamTurn ranges over agent.Run()'s event stream and emits transient activity based on what it sees:

  • before the loop: WriteActivity("thinking")
  • on a function-call event: WriteActivity("executing")
  • on a function-response event: WriteActivity("thinking")
  • after the loop: WriteActivity("working")

This stays self-contained — no Scion-specific code in core-agent's library. If a future adapter needs control-flow callbacks (abort tool calls, substitute responses), we'll expose ADK's BeforeToolCallback etc. on agent.New then; today, no consumer needs that.

Sticky vs transient
  • Transient (high-frequency, observation-only): atomic write to $HOME/agent-info.json. Cheap.
  • Sticky (low-frequency, hub-notifying): sciontool status <type> <message> subprocess. The model invokes these intentionally via the sciontool_status ADK tool — it owns the decision of when the task is "done" or it's "waiting on input."

WriteActivity reads the current activity first and refuses to overwrite a sticky one with a transient. This matches the Python adapter's semantics exactly.

Env-var contract
Var Source Purpose
GOOGLE_API_KEY user / Scion Gemini API key.
GEMINI_API_KEY Scion's Gemini harness Bridged to GOOGLE_API_KEY at startup if the latter is unset.
ANTHROPIC_API_KEY user Anthropic API key (when model.provider: anthropic).
HOME container Where agent-info.json lives. Falls back to /home/scion.
WORKSPACE_ROOT Scion (optional) Honored by core-agent's path-scope check via cwd.

What's not in this PR

  • No Anthropic-specific path; the adapter uses whichever provider .agents/config.json selects.
  • No subagent tool — that lands with core-agent's M3.
  • No CI image build — the Dockerfile is a template; consumers build it locally with their own scion-base.

Documentation

Overview

Command scion-agent runs core-agent inside a Scion-managed container. It mirrors cmd/core-agent's wiring (config / gate / model / built-in tools / MCP / skills / instruction loading) but replaces the interactive REPL with the Scion lifecycle contract:

  1. --input <task> seeds the first turn (Scion's harness appends this when starting the agent with a task).
  2. Each turn ranges over agent.Run()'s event stream and emits transient activity (thinking/executing/working) to $HOME/agent-info.json so Scion's UI can show what's happening.
  3. After each turn, stdin is read for follow-up messages — `scion message <agent>` delivers them via tmux send-keys, so this is just a line scanner.
  4. The model reports sticky lifecycle states (ask_user, task_completed, etc.) by calling the sciontool_status ADK tool, which shells out to scion's `sciontool` binary.

Outside a Scion container (no $HOME, no sciontool on PATH) the adapter still works — the lifecycle hooks degrade to no-ops so the same binary is usable for local development.

Package main's sciontool.go is a thin Go wrapper around scion's container-side `sciontool` CLI binary (scion/cmd/sciontool/). It does not reimplement sciontool — it just speaks the same status-emission contract:

  1. Transient activity (thinking/executing/working) is written directly to $HOME/agent-info.json via atomic rename. Cheap and high-frequency.
  2. Sticky transitions (waiting_for_input/blocked/completed/ limits_exceeded) shell out to `sciontool status <type> <message>` so scion's hub gets notified in addition to the local file.

Both paths degrade gracefully when running outside a scion container (sciontool not on PATH, no $HOME, etc.) so the same binary is runnable for local development without a Scion runtime.

Mirrors scion/examples/adk_scion_agent/sciontool.py one-for-one.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL