Gas City v1.3.0
Highlights
- Packs v2 is now the default pack model: pack identity, locks, includes,
overlays, registry metadata, and install/update flows are explicit instead
of being inferred from hidden built-ins. gc initnow starts new cities from the publicgascitymethodology pack,
embedded in the release and installed through the normal pack machinery.- Built-in packs are no longer implicit magic. Cities should import the packs
they use, pin those imports inpacks.lock.toml, and rely ongc doctor --fixto repair missing explicit imports. - The pack registry command surface is available under
gc pack registry ...,
including publish-oriented commands for registry maintainers. - Early access: the
gascity-packscollection.gascity-packsis an
opt-in pack collection composed viapack.toml[imports]— featuring
gascity(planning/implementation, the bundledgc initdefault),
gastown(multi-agent orchestration), and the early-access build-methodology
packscompound-engineering(compound-build),gstack(gstack-build),
andsuperpowers(superpowers-build). Add one with e.g.
gc import add --name gc https://github.com/gastownhall/gascity-packs.git//gascity;
see the Troubleshooting section and the gascity-packs README for details. - Formulas v2 and
drainare in the release path. Thegascitypack uses
formula execution throughgc sling ... --on <formula>and drain-backed
implementation workflows. - Prompt and runtime hardening from the 1.3 cycle is included, including
sanitized deferred reminder fields, supervisor secret environment handling,
and managed Dolt/runtime reliability fixes.
Upgrading Notes
- Run
gc doctor --fixonce per existing city after upgrading. The 1.3
doctor owns the breaking migrations for explicit provider catalogs and
explicit pack imports/locks. The relevant checks areprovider-catalog,
builtin-pack-imports, andpackv2-import-state. - Provider references must be declared in
[providers]. Cities that set
workspace.provideror agent-levelprovidervalues now need matching
[providers.<name>]entries.gc doctor --fixappends missing built-in
aliases such as[providers.claude] base = "builtin:claude"; custom
providers still require hand-authored provider tables. - Built-in and gastown pack composition changed. Gas City no longer
relies on implicit built-ins or per-city.gc/system/packsmaterialization.
Existingworkspace.includes = [".gc/system/packs/..."], legacy public
gastown/maintenanceimport sources, superseded bundled pins, and stale
locks are migrated to explicit pinned imports inpack.tomlplus
packs.lock. - No control-dispatcher named session is generated. The control dispatcher
serves entirely via demand-scaling of the core pack'score.control-dispatcher
agent template (controller work routed throughgc.routed_to = "core.control-dispatcher"), so the on-demand[[named_session]]alias older
builds wrote is redundant.gc initno longer creates it, andgc doctor --fix(during a pack-layout migration) drops the stale alias from upgraded
cities so its "backing template not found … disabled" warning stops firing. - Generated configs no longer pin
formula_v2. Formula v2 is on by
default, sogc initomits the[daemon] formula_v2line instead of writing
the default value. An explicitformula_v2 = false(or the deprecated
graph_workflows = falsealias) is still honored and preserved on round-trip. gc session logs --tail Nno longer renders blank. Every transcript
entry that occupies a tail window now prints at least one line — a non-error
tool_resultshowstool_result: ok, and any otherwise non-rendering entry
(empty text, thinking, or an unrecognized block) shows(no displayable content)— so a tail landing on such entries can no longer produce empty
output.- The built-in Claude provider no longer declares a fresh-start
session_id_flag. Claude remains resume-capable, but Gas City now records
the provider-created session key after startup instead of passing a
preselected fresh-session ID. - The
gastownpack is now consumed from
github.com/gastownhall/gascity-packs. The old checked-in
examples/gastown/packs/gastowntree is gone. Move local customizations
into an explicitly imported pack instead of editing.gc/system/packsor
the retired vendored example path. - Fallback agents were removed. Packs that previously depended on a
fallback dog/worker must ship their own worker pool and formulas. Cross-pack
agent name collisions are now hard errors. - Public imports are intentionally small. Authored
[imports.<binding>]
tables exposesourceand optionalversion; olderexport,
transitive, andshadowkeys remain compatibility-only loader behavior,
not public schema. - Formula v2 targeted executions use
convoy_id, notbead_id.
Graph/formula v2 templates no longer receive{{bead_id}}; update them to
use the reserved{{convoy_id}}variable for the input convoy. Formula v2
rejects authored inputs namedconvoy_idorbead_id, and{{issue}}
remains only a temporary compatibility alias that should be migrated too.
Changed
-
Version pins on builtin packs are honored: the binary only pre-seeds
its embedded content at each pack's canonical pin. Previously the
bundled synthetic cache served the running binary's embedded bytes for
ANY commit pinned on a bundled source — editing the pin changed nothing.
Now only the canonical pin (the onegc initwrites) resolves from the
embedded copy; a bundled source pinned at any other commit behaves
exactly like a regular remote import:gc import installfetches that
exact commit from git, validation uses the git checkout, and the cache
slot uses the plain remote key. Cities on canonical pins keep working
fully offline, including across binary upgrades that keep the pin
constants; releases that bump a canonical pin migrate existing cities
viagc doctor --fix(superseded canonical pins are rewritten to the
current one). -
Builtin packs are no longer materialized into cities; they compose via
pinned imports resolved from the user-global pack cache. The per-city
.gc/system/packstree is retired (and pruned on sight):gc initnow
writes pinned[imports.core]/[imports.bd]entries into pack.toml plus
a matching packs.lock, and the gc binary self-heals the GC_HOME cache
($GC_HOME/cache/repos) with its own embedded content so the pins resolve
offline. Thebuiltin-pack-includesdoctor check became
builtin-pack-imports: it migrates legacyworkspace.includes = [".gc/system/packs/..."]cities by stripping the includes, upserting the
pinned imports (creating a minimal pack.toml for legacy cities), and
refreshing packs.lock and the cache. The bd lifecycle script moved behind
a stable per-city shim at.gc/scripts/gc-beads-bd.shthat execs the
cache-resolved bundled script; provider normalization still recognizes
the legacy materialized path. All repo-cache roots (packman install,
config resolution, doctor) now uniformly resolve via GC_HOME instead of
mixing$HOME/.gcand GC_HOME.gc rig add --include <builtin>
canonicalizes to the bundled remote source and locks it. Migration:
rungc doctor --fixonce per existing city. -
The registry
gascityplanning pack is bundled and offered by the init
wizard.gc initnow offersgascityas a config template alongside
minimal/gastown (also via--template gascity), wiring the pinned public
import from gascity-packs the same way the gastown template does. The
pack is embedded from thegithub.com/gastownhall/gascity-packsmodule
root, so the pin resolves offline from the bundled synthetic cache. -
The bundled gastown pack is now a Go module dependency, not a checked-in
copy.examples/gastown/packs/gastownis gone; the gc binary embeds the
pack fromgithub.com/gastownhall/gascity-packs(pinned in go.mod to the
registry release commit), and the example city composes gastown through
the pinned public registry import plus a committedpacks.lock— the same
shapegc initwrites — resolved offline from the bundled synthetic
cache.scripts/update-bundled-gastown-packno longer writes a vendored
tree; it bumps the go.mod pin, thePublicGastownPack*constants, and the
example pins from the latest registry release, and--checkverifies the
pinned module content against the registry hash. The gastown integration
tests inexamples/gastownnow run against the module-embedded bytes, so
a runtime/pack mismatch fails in gascity CI. -
The bundled maintenance pack was folded into the core pack, and builtin
packs compose only through explicit pinned imports. The bundledcore
pack carries the gc-* skills, default worker prompts, core formulas, the
mechanical housekeeping orders that used to ship in the maintenance pack
(gate-sweep, orphan-sweep, cross-rig-deps, order-tracking-sweep,
spawn-storm-detect, prune-branches, wisp-compact, nudge-mail-sweep,
nudge-on-route, cascade-nudge-on-blocker-close), the check-binaries doctor
check, and the per-provider hook overlays. Config load no longer splices
builtin packs into composition:gc initwrites explicit[imports.core]
and, for default bd-provider cities,[imports.bd]entries into
pack.toml, plus a matchingpacks.lock. The fixable
builtin-pack-importsdoctor check repairs missing imports and migrates
legacyworkspace.includes = [".gc/system/packs/..."]cities by stripping
those includes, adding the pinned imports, and pruning stale
.gc/system/packsmaterialization. Migration: rungc doctor --fix
once per existing city. -
The implicit fallback dog is gone, and the
fallbackagent field was
removed. The gastown pack now owns its dog pool outright
(agents/dog/, themed, withmol-shutdown-dance), and the dolt pack
keeps its own dolt dog for Dolt maintenance formulas. The
fallback-agent resolution mechanism (fallback = true, non-fallback
wins, first-loaded wins) was removed: cross-pack agent name collisions
are now hard errors, and a stalefallbackkey in a V2
agents/<name>/agent.tomlis ignored while a V1 inline[[agent]]
entry fails the pack's unknown-key gate. External packs that relied on
the bundled fallback dog must define their own worker pool (or route
work to a pool they ship themselves).
Added
-
Early access: the public
gascity-packscollection. v1.3.0 ships the
first early-access release of
gascity-packs— an opt-in
collection of Gas City packs composed viapack.toml[imports]. Add one
with e.g.
gc import add --name gc https://github.com/gastownhall/gascity-packs.git//gascity.
Featured packs:gascity— planning & implementation workflow pack; bundled in the
release and the defaultgc inittemplate (also--template gascity).gastown— multi-agent orchestration / default coding workflow pack;
bundled and offered bygc init(--template gastown).compound-engineering(compound-build) — Every Inc.'s Compound
Engineering methodology as a build factory: brainstorm/plan → persona-panel
plan review → implement → wide reviewer-persona fanout → resolution.gstack(gstack-build) — garrytan/gstack founder-style sprint:
office-hours intake → multi-perspective plan review → staff review → QA →
security → release readiness.superpowers(superpowers-build) — Jesse Vincent's Superpowers skill
library as a build factory: brainstorm → written-spec approval → per-task
TDD → spec-compliance then code-quality review.
gascityandgastownare in the supported registry; the three
build-methodology packs (compound-engineering,gstack,superpowers) are
early access and each importgascityasgc. See the gascity-packs README
for the full list and import instructions.
-
Formulas v2 and
drainare the supported path for new graph
workflows. The v2 compiler emits flat workflow graphs with
controller-owned control/finalize beads, anddrainis now the canonical
fan-out primitive for scattering convoy members into per-item formula runs.
The bundledgascityplanning pack ships graph.v2 build and implementation
formulas, including the mayor skill's documentedgc sling ... --on <formula>launch flow and drain-basedimplementworkflow, so new Gas City
methodology workflows no longer need the legacygc.output_json/tally fan-out
pattern. -
Proxy-process workspace services now receive
GC_SERVICE_SECRETS_DIR
(<GC_SERVICE_STATE_ROOT>/secrets) in their environment, alongside the
existingGC_SERVICE_*variables. The directory is scaffolded at0700
by the service state-root setup and is the sanctioned home for
pack-managed credentials (bot tokens etc.), so pack services can rely on
the explicit contract instead of deriving the path from
GC_SERVICE_STATE_ROOT. See #3429. -
gc nudge drain --injectnow prepends a one-line current-time stamp
(operator-local + UTC + epoch) to itsUserPromptSubmithook output, giving
agents a live clock in context every turn. The local zone follows the host
(time.Local/$TZ) or theGC_OPERATOR_TZoverride; disable with
GC_INJECT_CLOCK=0. Folded into the existing nudge inject, so it adds zero
extra hook subprocesses per turn. See #3036. -
The supervisor now merges a machine-local secrets file
(${GC_HOME}/secrets.env, dotenv syntax) into the launchd plist / systemd
unit environment on every service-file regeneration. This fixes provider
credentials being dropped whengc startruns from a shell that did not
export them (e.g. at login or after a reboot), which previously caused
silent provider auth failures. Only keys already eligible for the supervisor
environment are merged (provider credentials plusGC_SUPERVISOR_ENV
opt-ins); a value exported in the calling shell still takes precedence, and
GC_SUPERVISOR_OMIT_PROVIDER_CREDS=1suppresses provider credentials from
both sources. -
GC_DOLT_SYNC_PUSH_TIMEOUT_SECSconfigures the SQL-mode push wall-clock
ceiling forgc dolt sync(default 1800s, replacing the prior fixed 120s
that SIGKILLed large first pushes). Metadata queries keep their own 120s
bound. -
ENOSPC pre-flight for managed Dolt (
GC_DOLT_MIN_FREE_BYTES,
GC_DOLT_WARN_FREE_BYTES): managed-Dolt startup and the store-maintenance
compaction loop now check container free space viastatvfs(2)before
performing disk-growing operations. Below the critical floor (default
500 MiB) startup is refused and compaction is skipped; below the soft floor
(default 2 GiB) agc.store.disk_warnevent is emitted and operations
proceed. Fails open on probe error and is disabled entirely when
GC_DOLT_MIN_FREE_BYTES=0. Usesf_bavail(APFS-safe — excludes purgeable
space). Addresses the root trigger of the 2026-06-01 fleet-drain incident.
Fixed
-
The synthetic bundled-pack cache key now folds in the running binary's
embedded-pack content hash, so twogcbinaries with different bundled-pack
content resolve to different cache directories instead of fighting over one.
Previously the cache directory was keyed only on namespace+source+commit, so a
version-skewed deploy (controller and agents on differentgcbuilds) left
both binaries materializing one shared directory in turn: eachgc import installwas promptly clobbered by the other binary, re-wedging everygc bd
citywide with "bundled pack cache content hash does not match current binary"
roughly hourly. With the content hash in the key,gc import installfor a
given binary sticks for that binary regardless of other versions running.
Note: deploying a binary with changed bundled-pack content still requires a
one-timegc import install(or bootstrap materialize) to populate the new
cache directory; that install is now durable rather than transient (ga-s9p). -
Pool respawn after
gc runtime drain-ackno longer waits up to a full patrol
interval (default 60 s) before the replacement session starts. The async kill
goroutine now pokes the controller once after the session is gone so Phase 2
(finalize bead + spawn replacement) runs on the next event tick. Fixes the
TestLifecycle_DrainAckResponsiveRespawn/prequeued_respawn_2364Tier B
nightly regression (ga-ryhnhd, #2364, #2251). -
gc dolt syncnow emits per-mode diagnostics on push failure instead of a
generic "push failed": a TIMEOUT message naming the ceiling and
GC_DOLT_SYNC_PUSH_TIMEOUT_SECSon exit 124, the underlying exit code on
other failures, and the underlying dolt stderr. The replayed stderr cannot
leakGC_DOLT_PASSWORD: the password reaches dolt via theDOLT_CLI_PASSWORD
environment variable, never as an argv flag.GC_DOLT_SYNC_PUSH_TIMEOUT_SECS
rejects every numeric-zero form (0,00,000, ...) -- not just the
literal0-- because GNUtimeouttreats a zero duration as "disable the
timeout", which would push unbounded. A failure to create the stderr-capture
temp file now degrades to a per-database error rather than aborting the whole
run. -
Interactive
gc session newtmux sessions now scroll tmux scrollback on the
mouse wheel instead of leaking the wheel to the focused TUI (Claude Code's own
history, a pager, or the shell). The gastown pack bindsWheelUpPane→copy-mode
andWheelDownPane→passthrough, and the runtime resolves interactive sessions
to mouse-on across every create seam so tmux preserves themouse onset at
session create: thegc session newCLI — both the managed-deferred reconciler
start (templateParamsToConfig, forsession_origin=manualsessions) and the
unmanaged direct start (workerSessionCreateHints) — plus the API
provider/named paths (sessionCreateHints). Resume keeps mouse-on too
(sessionResumeHints), so the wheel survives suspend/restart. Headless agent
sessions stay mouse-off (controller-poll safety) — they resolveMouseOnfrom
the agent template path (cfgAgent.MouseModeOn()), which is unchanged and has
neither themanual/namedinteractive marker. Replaces the portharbour
po-vtg2 city-localset-hookstopgap with the in-source fix. Refs: ga-c4w.
Troubleshooting (packs, imports, registry)
v1.3.0 changed pack composition: built-in/gastown packs are now consumed via
explicit pinned [imports] in pack.toml + packs.lock, served from a
content-hashed cache under ~/.gc/cache/repos/ (nothing is materialized into
.gc/system/packs anymore). Most upgrade issues are fixed by one command — run
it once per existing city after upgrading:
gc doctor --fix
It owns the mechanical migrations (provider-catalog, builtin-pack-imports,
packv2-import-state): it adds missing pinned imports, strips legacy
workspace.includes / [packs] surfaces, re-pins superseded canonical
versions, refreshes packs.lock + cache, and prunes leftover .gc/system/packs.
| Symptom | Cause | Fix |
|---|---|---|
does not import required builtin pack(s) core; run "gc doctor --fix"
| City predates explicit [imports].
| gc doctor --fix
|
workspace.includes is deprecated in v2; use [imports] / [packs] is deprecated / unsupported PackV1
| Legacy v1 composition surfaces. | gc doctor --fix (a fragment-authored [packs] may need a manual edit)
|
remote import <src> is not installed (missing packs.lock); run "gc import install"
| Declared import lacks a lock pin, or its cache checkout is absent. | gc import install (diagnose with gc import check / gc import status)
|
synthetic cache is invalid at <dir>: missing bundled pack cache marker
| Bundled synthetic cache present but invalid (an absent cache self-heals offline). | gc import install
|
N bundled import(s) pinned at a superseded canonical version
| Stale packs.lock from an older gc.
| gc doctor --fix (offline re-pin)
|
durable import(s) use command-time registry selectors
| A registry: selector was written into pack.toml.
| Manual edit — replace with the concrete source (gc pack registry show <pack>)
|
gc start prints FATAL: pack schema 2 not supported
| A stale supervisor still on the old binary. | let gc start auto-restart, or systemctl --user restart gascity-supervisor
|
See also: docs/getting-started/troubleshooting.md,
docs/reference/system-packs.md, docs/guides/understanding-packs.md,
docs/guides/shareable-packs.md, docs/guides/registry-showcase.md,
docs/troubleshooting/gc-start-walkthrough.mdx, and the gc doctor /
gc import / gc pack registry references in docs/reference/cli.md.
Validation
- Preflight passed on
origin/mainat
e02391fe7f0b4281cd10afc4f9293412467f529d; the release branch
release/v1.3.0was prepared from that SHA. - Feature readiness was closed before starting the release branch, including
the defaultgascitypack work, explicit built-in pack migration, Packs v2
registry flow, Formulas v2/drain path, and prompt-safety fixes. - Remaining release gates are still staged by the formula: local RC, Homebrew
core readiness, remote RC, changelog promotion, final tag publication,
GitHub release workflow verification, and Homebrew tap smoke.
Homebrew
- The
gastownhall/gascitytap remains asset-based for existing users. - Homebrew/core submission uses a separate source-built formula.
- Install from the tap with
brew install gastownhall/gascity/gascity.
Contributors
Thanks to everyone who contributed to v1.3.0 (between v1.2.1 and v1.3.0):
@8888, @A3Ackerman, @McKean, @Perttulands, @Rome-1, @Wescome, @Wldc4rd, @alexcasper, @azanar, @benw5483, @bourgois, @boylec, @brandonmartin, @brian-amos-embedded, @coffeegoddd, @csells, @cstar, @curtisjm, @dcgas, @donbox, @duncan4123, @eric-jones, @eric-richardson1, @esciara, @hexsprite, @idvorkin-ai-tools, @itsthatriver, @iwata-1116, @jjgarzella, @johnzook, @jsgerman-oss, @julianknutsen, @kab0rn, @kevmoo, @lucasfuad, @lvanderbijl-kry, @mattiasw, @mike-matchpoint, @mikeakers, @myster-t, @nicholasspencer, @ooa-andera, @outdoorsea, @quad341, @realies, @reggieperry, @rileywhite, @rjgeng, @rogerluan, @sarendipitee, @scarson, @sfncore, @sjarmak, @steveyegge, @tesdal, @tim-white87, @vbtcl, @wynged
New Contributors
- @reggieperry made their first contribution in #2651
- @duncan4123 made their first contribution in #2377
- @kevmoo made their first contribution in #2682
- @jjgarzella made their first contribution in #2469
- @mike-matchpoint made their first contribution in #2712
- @alexcasper made their first contribution in #2733
- @8888 made their first contribution in #2676
- @Wldc4rd made their first contribution in #2721
- @curtisjm made their first contribution in #2824
- @Perttulands made their first contribution in #2677
- @rogerluan made their first contribution in #2653
- @idvorkin-ai-tools made their first contribution in #2854
- @Wescome made their first contribution in #2543
- @McKean made their first contribution in #2641
- @dcgas made their first contribution in #2939
- @cstar made their first contribution in #2925
- @brian-amos-embedded made their first contribution in #3025
- @jsgerman-oss made their first contribution in #3068
- @mikeakers made their first contribution in #3069
- @ooa-andera made their first contribution in #3112
- @coffeegoddd made their first contribution in #3240
- @benw5483 made their first contribution in #3276
- @nicholasspencer made their first contribution in #3278
Recommended Reading
- Installation guide
- Troubleshooting guide
- Understanding packs
- System packs reference
- CLI reference
- Config reference
Full Changelog: v1.2.1...v1.3.0