Getting started
This guide builds and runs the Petclinic reference application using ordinary Go source and inspectable generated Go. It requires Go 1.26.5. No database, container, or network download is needed after the application’s declared module and tool dependencies are present.
Authorize the CLI
From the consuming application’s module, select compatible toolchain versions with ordinary Go commands:
go get -tool github.com/spice-framework/toolchain/cmd/spice@<version>go get -tool github.com/spice-framework/toolchain/cmd/spice-annotation-core@<version>go tool github.com/spice-framework/toolchain/cmd/spice versionThe application’s go.mod authorizes the executable dependencies. Core does
not build or download the CLI, and Spice does not maintain a second plugin
dependency system. Release archives are produced by the toolchain repository’s
exact-tag process described in releasing.md.
Create a clean application
spice new creates a valid-Go application and its ordinary go.mod without
running a Go command, downloading a module, initializing Git, or overwriting a
non-empty directory:
spice new --module example.com/acme/hello --directory hellocd hellogo mod downloadgo tool github.com/spice-framework/toolchain/cmd/spice generate --target Hello .go tool github.com/spice-framework/toolchain/cmd/spice verify .go tool github.com/spice-framework/toolchain/cmd/spice run --target Hello .The target name and generated-package ID derive from the final module-path
segment through the same compiler-owned normalization used during analysis.
Initial generation supplies the missing generated package through an in-memory
overlay; no physical stub is created. Run go mod tidy after that first
generation. --spice-version selects an exact pre-release or release when the
CLI build should not select its own version. --replace is an explicit local
development option and is never emitted by a release workflow by default.
Add an ordinary dependency through a previewed standard Go operation:
spice add golang.org/x/sync/errgroup@v0.22.0spice add --apply golang.org/x/sync/errgroup@v0.22.0The first command runs go get only against a temporary sibling modfile and
prints the exact bounded go.mod/go.sum diff. --apply creates a fresh plan,
prints it, and writes its exact after-images only while both original file
hashes still match. Add --tool to use Go’s go get -tool authorization path.
These commands are explicit network-capable developer actions; normal
analysis, generation, and editor operation remain offline and read-only.
Inspect the application
Petclinic is an independent consumer module at
spice-framework/petclinic.
Clone it separately from the core framework. Its go.mod selects an immutable
Spice version, authorizes the CLI and annotation tool with standard Go tool
directives, and contains no local replace:
git clone https://github.com/spice-framework/petclinic.gitcd petclinicgo tool github.com/spice-framework/toolchain/cmd/spice verify .go tool github.com/spice-framework/toolchain/cmd/spice generate --check --target Petclinic .The process entrypoint in main.go is valid Go:
// @import { Application } from "github.com/spice-framework/spice/annotation/core"// @import { Enable } from "github.com/spice-framework/spice/annotation/management"
// @Application// @Enable(expose=["health", "readiness", "info"], access="loopback")func main() { os.Exit(spiceapp.Main(os.Args[1:]))}@import is file-scoped and explicit. The imported descriptor is a real Go
function that the compiler decodes without executing. The target module’s
go.mod is the only authority that permits its handler tool to run.
spiceapp is the ordinary Go import alias for
github.com/spice-framework/petclinic/internal/spicegen/petclinic.
Verify and generate
From the standalone Petclinic root, use its authorized Spice tool dependency:
go tool github.com/spice-framework/toolchain/cmd/spice verify .go tool github.com/spice-framework/toolchain/cmd/spice generate --check --target Petclinic .generate --check is read-only. To create or update owned artifacts, run the
same command without --check. The output has three clear roles:
internal/spicegen/petclinic/spice_assembly_gen.go bounded construction-phase sequencinginternal/spicegen/petclinic/spice_{contracts,configuration,providers}_gen.go typed contracts, configuration metadata, and dependency constructioninternal/spicegen/petclinic/spice_http_gen.go HTTP and management coordinationinternal/spicegen/petclinic/spice_http_route_<symbol>_<id>_gen.go one stable, source-linked route adapterinternal/spicegen/petclinic/spice_{features,lifecycle,command}_gen.go optional features, reusable lifecycle, and process entrypoint behaviorinternal/spicegen/petclinic/sources/<package>/<source>_spice_gen.go one source-owned unit with direct construction, binding, and assertionsinternal/spicegen/petclinic/artifacts/openapi.json generated non-Go contracts.spice/petclinic.manifest.json hashes, roles, source origins, and generated rangesGenerated files are committed, formatted Go. The ownership manifest prevents
Spice from overwriting manual edits or unrelated files. Run go tool github.com/spice-framework/toolchain/cmd/spice generated --source main.go to
locate the source-owned application unit, or pass that generated path with
--generated for the reverse mapping.
Run and debug
Start the application:
$env:SPICE_PETCLINIC_ADDRESS = "127.0.0.1:8080"go tool github.com/spice-framework/toolchain/cmd/spice run --target Petclinic .SPICE_PETCLINIC_ADDRESS=127.0.0.1:8080 \ go tool github.com/spice-framework/toolchain/cmd/spice run --target Petclinic .Open http://127.0.0.1:8080/. Search owners, edit an owner, add a pet and a
visit, and inspect /vets. Management routes under /actuator/ accept only a
direct loopback peer.
spice run generates safely and then builds the complete package with
-trimpath; it never compiles a temporary source fragment. A Go debugger sees
normal generated calls and steps directly into handwritten constructors,
controllers, and repositories. The GoLand plugin uses this complete-package
path for Run and generates before native Go/Delve Debug.
Use the development loop
Replace run with dev. Spice watches relevant files, debounces changes, and
gracefully replaces the process only after analysis, generation, and build
succeed:
go tool github.com/spice-framework/toolchain/cmd/spice dev --target Petclinic .Add // @Unknown below // @Application and save. The compiler reports an
exact diagnostic while the last-known-good process remains live. Remove the
invalid annotation and save; Spice regenerates and restarts the package.
Test a generated application
Use ordinary Go tests for domain code. For generated wiring, create a typed
context with spicetest.NewContext; for routes, use spicetest.NewHTTP; for
database behavior that must roll back, use spicetest.NewSQL. These helpers
accept typed generated applications and never use reflection, provider
replacement, or a runtime container.
Focused module tests retain ordinary Go controls:
go tool github.com/spice-framework/toolchain/cmd/spice test --module example.com/shop/orders --race --count=1 ./...See testing.md for complete examples and cleanup behavior.
Next steps
- application.md explains discovery and generated ownership.
- annotations.md lists the supported annotation contracts.
- Spice for GoLand installs and verifies the independently versioned primary editor experience.
- spring-to-spice.md maps familiar Spring concepts.
- developer-proof.md runs the decisive editor/dev proof.