本页还没有译文
本页 44 段还没译成繁體中文,下面显示的是英文原文。Configuring an Agent
还没翻译译自英文(docs.gascity.com)本页 44 段都还没译
The Agents tutorial shows the fast path: drop an
agent.toml with a provider and a prompt, and sling work to it. This guide is
the how-to reference for everything you can tune underneath that — the
five independent axes of an agent — with a deep dive on the upstream
axis (who serves the model), which is the newest knob.
For the exact field list and types, see the generated Config Reference. This guide explains how the pieces fit; the reference is the authoritative spec.
The five axes
An agent is the composition of five orthogonal choices. You set each one independently — change the model without touching the harness, switch who serves the model without changing the box, and so on.
| Axis | Question | Where you set it | Example |
|---|---|---|---|
| Harness | which agent CLI? | agent provider | provider = "claude" |
| Model | which model label? | agent option_defaults.model | option_defaults = { model = "sonnet" } |
| Upstream | who serves the model? | agent upstream + [upstreams.<name>] | upstream = "bedrock" |
| Transport | how does gc drive it? | agent session | session = "acp" |
| Runtime | where does it run? | city [session] provider / GC_SESSION | provider = "k8s" |
A note on the word "provider." It is overloaded by history. In an
[[agent]]/agent.tomlblock,providerselects the harness (the agent CLI —claude,codex, …). In the city[session]block,providerselects the runtime backend (where sessions run —tmux,k8s, …). They are different axes; this guide always says "harness" or "runtime" to disambiguate.
The first three axes (harness, model, upstream) are per-agent. Transport is per-agent. Runtime is city-/environment-wide (every session in a city runs on the same backend).
Axis 1 — Harness (provider)
The harness is the agent CLI gc launches and drives. Gas City ships built-in
presets for the popular ones — claude, codex, gemini, grok, kimi,
cursor, copilot, amp, opencode, and more — so the minimal agent is just:
# agents/reviewer/agent.toml
dir = "my-project"
provider = "codex"Each preset defines the command, default args, resume behavior, prompt
delivery, and the model + upstream contracts (below). Customize one with a
city-level [providers.<name>] block: a same-named block merges over the
built-in (you set only what you change), and a differently-named one can inherit
from any provider via base:
# city.toml — customize the built-in claude harness
[providers.claude]
args = ["--verbose"] # everything else inherits from builtin:claude
# …or define a new harness that inherits from a built-in
[providers.claude-fast]
base = "builtin:claude"
option_defaults = { model = "haiku" }For copy-paste setup of each built-in harness — the env vars it reads and the direct / custom-endpoint / model permutations — see Harness Recipes. See Understanding Packs for shipping a harness preset as a reusable pack.
Axis 2 — Model (option_defaults.model)
A harness exposes its configurable knobs through an options schema. The
model option is the common one; selecting a value injects the right CLI flags
for that harness — you pick an abstract label, the harness renders the flag.
# agents/reviewer/agent.toml
provider = "codex"
option_defaults = { model = "sonnet", permission_mode = "plan" }option_defaults is a map of option key → choice value. The provider's
options_schema declares the allowed choices and the flag_args each one emits
(see ProviderOption / OptionChoice in the reference).
This is why you write model = "sonnet" and not a raw --model flag: the schema
keeps the model selection portable and the flags server-side.
Axis 3 — Upstream (who serves the model)
This is the newest axis. The model is what you ask for; the upstream is who serves and resolves it — direct Anthropic, Bedrock, Vertex, a self-run proxy, an OpenAI-compatible gateway. Switching upstream changes the base URL and credentials the harness talks to, without changing the model, the harness, or the box — and (post-un-weld) without re-provisioning: it relaunches the agent in the warm box.
Declare an upstream, select it
Upstreams are named presets at the city level; an agent selects one by name.
# city.toml
[upstreams.bedrock]
description = "Anthropic models via AWS Bedrock"
base_url = "https://bedrock.example.com/anthropic"
api_key = "$AWS_BEDROCK_KEY" # a $VAR ref — never inline a secret
[agent_defaults]
upstream = "bedrock" # city-wide default for every agent# agents/reviewer/agent.toml — this agent overrides the default
upstream = "anthropic-direct"Resolution order for an agent's upstream: agent upstream → agent_defaults.upstream
→ unset (no upstream env injected; the harness uses whatever is ambient).
Abstract vs. raw — and why abstract is portable
An upstream can be written two ways, which compose:
Abstract (portable). base_url, api_key, and auth_token are
harness-agnostic. The resolver renders them onto that harness's env-var
names, declared by the harness as its upstream_env binding. So one upstream
works on any harness:
[upstreams.bedrock]
base_url = "https://bedrock.example.com/anthropic"
api_key = "$AWS_BEDROCK_KEY"- on a
claudeagent →ANTHROPIC_BASE_URL+ANTHROPIC_API_KEY - on a
codexagent →OPENAI_BASE_URL+OPENAI_API_KEY
The built-in harnesses ship their bindings out of the box (claude → ANTHROPIC_*,
codex → OPENAI_*, gemini → GOOGLE_GEMINI_BASE_URL/GEMINI_API_KEY, and so
on). A custom harness declares its own:
[providers.myharness.upstream_env]
base_url = "MYHARNESS_BASE_URL"
api_key = "MYHARNESS_API_KEY"An abstract field with no matching harness binding (and no override, below) is a hard error, never a silent no-op — you find out at resolution time, not when the agent quietly talks to the wrong endpoint.
Raw (escape hatch). When the abstract trio doesn't cover what a harness
needs, set raw env keys with env. They merge after the abstract render, so
they win:
[upstreams.bedrock]
base_url = "https://bedrock.example.com/anthropic"
api_key = "$AWS_BEDROCK_KEY"
[upstreams.bedrock.env]
AWS_REGION = "us-east-1"
CLAUDE_CODE_USE_BEDROCK = "1"Gateway harnesses — the per-field override
Some harnesses are gateways: one CLI (e.g. opencode) fronts many upstreams
whose credential env var is upstream-dependent (GROQ_API_KEY for Groq,
CEREBRAS_API_KEY for Cerebras, …). Such a harness has no single binding to
declare. The upstream names its own target with the per-field *_env overrides:
[upstreams.groq]
api_key = "$GROQ_KEY"
api_key_env = "GROQ_API_KEY" # this upstream renders api_key to GROQ_API_KEYPer-field precedence is: upstream *_env override → harness binding → hard
error. Native single-upstream harnesses stay fully abstract via their binding;
gateways supply the name themselves.
Secrets and fingerprints
- Secrets are never inlined. Abstract and raw values may reference controller
env vars with
$VAR/${VAR}, expanded at resolution — soapi_key = "$ANTHROPIC_API_KEY"keeps the secret out ofcity.toml. - Switching the upstream name relaunches the agent in the warm box (it is a launch-half fingerprint change). Rotating the key within the same upstream moves no fingerprint — the resolved serving env is excluded from the hash, so a credential rotation never churns live sessions.
Axis 4 — Transport (session)
The transport is how gc drives the harness. The default is tmux (gc sends
keystrokes and captures the pane). Set session = "acp" to drive the harness
over the Agent Client Protocol (JSON-RPC over
stdio) instead — the harness's resolved provider must declare supports_acp = true.
# agents/reviewer/agent.toml
provider = "claude"
session = "acp" # drive over ACP instead of tmuxAxis 5 — Runtime (where it runs)
The runtime is where the session's box lives. It is selected city-wide via the
[session] block (or the GC_SESSION environment variable), not per-agent:
# city.toml
[session]
provider = "k8s" # run every session in a Kubernetes podBuilt-in runtime backends: tmux (local, default), subprocess (local,
headless), k8s (pods), ssh:user@host (a remote box over SSH), and
exec:<script> (a pluggable exec session pack
— this is how sandbox / micro-VM runtime packs plug in). GC_SESSION=ssh:user@host
or GC_SESSION=exec:<runtime-pack> selects one without editing city.toml.
An agent that never needs interactive attach can set
attach = falseto let gc pick a lighter runtime (subprocess) where the city allows it.
Putting it together
A fully-specified agent that runs Claude on Bedrock, in a Kubernetes pod, driven over tmux:
# city.toml
[session]
provider = "k8s"
[upstreams.bedrock]
base_url = "https://bedrock.example.com/anthropic"
api_key = "$AWS_BEDROCK_KEY"
[upstreams.bedrock.env]
AWS_REGION = "us-east-1"# agents/reviewer/agent.toml
dir = "my-project"
provider = "claude" # harness
option_defaults = { model = "opus", permission_mode = "plan" } # model
upstream = "bedrock" # who serves it
# session omitted → tmux transport; [session] above → k8s runtimeInspect the result without launching anything:
$ gc prime my-project/reviewer # the rendered prompt
$ gc doctor # validates your city / agent configA missing upstream binding (an abstract field with no harness
upstream_envand no*_envoverride) is reported as a hard error when the agent's session is resolved — so a misconfiguration fails the launch loudly rather than silently talking to the wrong endpoint.
Where to go next
- Spec / reference: the authoritative field list and types — Config Reference. Wire contract for exec runtimes — Exec Session Provider.
- Packs: ship harness presets — a provider and its
upstream_envserving-env binding — as reusable, shareable bundles — Understanding Packs, Shareable Packs. (A pack may also declare named[upstreams.<name>]endpoint presets as a base that the importing city inherits — import the pack, get the upstream for free. A city's own[upstreams.<name>]incity.tomlor a city fragment overrides a pack-provided one of the same name. A pack-carried[upstreams.<name>](itsbase_url, credential env-refs, and raw[env]block) is TRUSTED configuration — the same trust level as a pack'sprovider.command— so only import packs you trust.) - Tutorial: the guided walkthrough that introduces agents — Tutorial 02 — Agents.