golemcloud/golem/golem-add-agent-go
- community
Checking that the SKILL.md file is still in the repository.
Adding a new Go agent to a Golem component. Use when the user asks to create, add, or define a new agent type, split an agent into definition/implementation, or add agent methods in a Go Golem project.
Install
npx vskill@latest install golemcloud/golem/golem-add-agent-goSKILL.md
Adding a New Agent to a Go Golem Component
Overview
An agent is a durable, stateful unit of computation in Golem. In Go each agent is split across two packages:
- a state-free definition (
package <name>) — the agent's identity, its method descriptors, and the input/output types. Other agents import this package to call it. - an implementation (
package impl, in a nestedimpl/subpackage) — the private state and the method handlers. Importing this package registers the agent with the SDK.
This split lets agents call one another without a Go import cycle, and keeps state private to the implementation.
Steps
- Create the definition — add
agents/<name>/<name>.gowithpackage <name>. - Declare identity + types — an
IDstruct (its fields are the constructor parameters), plus any input/output structs. - Define the agent and its methods —
golem.DefineAgent+ oneAgent.Methoddescriptor per method. - Create the implementation — add
agents/<name>/impl/impl.gowithpackage impl: a privatestate,Agent.Implement, and oneimpl.Handleper method. - Wire it in — blank-import the impl package in
main.go. - Build — run
golem build.
Definition (agents/counter/counter.go)
golem.Unit is the empty parameter/result placeholder (a method with no input or no output).
golem.Description(...) describes a method and golem.PromptHint(...) tells AI callers when to use it; Spec.PromptHint does the same for creating the agent.
Spec.Dependencies lists other agents of the same component this one calls (Dependencies: []golem.AgentDependency{billing.Agent}); they are published with the agent's metadata.
Implementation (agents/counter/impl/impl.go)
The handler receives *golem.Context[state]; ctx.State is your *state. golem.Adapt0 adapts a no-input (*state) method into a handler; golem.Adapt adapts a one-input method.
Wiring: main.go
main.go (package main) blank-imports each agent's impl package so its registration runs on import, plus the SDK runtime:
Adding another agent = another agents/<name>/ folder + one more blank import here.
Custom Types
Parameter and result types are Go structs; each exported field becomes one WIT field, named by the Go name in lowerCamelCase with each initialism as one word (AmountCents → amountCents, UserID → userId). Two fields whose names map to the same schema name are a definition error.
- Use sized integers (
int64,uint64, …). Bareint/uintare rejected — their width is platform-dependent. time.Time,time.Durationandgolem.UUIDaredatetime,durationanduuid;golem.ParseUUIDreads one from text.- A
*Tfield meansoption<T>. A nil slice/map is an empty list/map, never "absent" — use*[]Tif you must distinguish. - Variants/enums are declared with
golem.DefineVariant/golem.DefineEnum. A variant case type is its payload; a case with no payload is an empty struct (type Cash struct{}). - When the payload cannot carry the variant's marker method without changing what it is — a
time.Time, agolem.Text, anOption, another variant — wrap it in a one-field struct and register it withgolem.WrappedCase.type At time.Timewould publish a different schema;type At struct{ Value time.Time }withWrappedCase[At]("at")publishesat(datetime). Unions havegolem.WrappedBranchfor the same reason.
Unstructured and Multimodal Content
For content a model or a person reads, use the content types. Tools and UIs recognise them by their role:
- A non-empty
URLrefers to the content; otherwiseTextorDatacarries it inline. golem.MultimodalOf[T]is a list of your own modalities, whereTis a variant registered withgolem.DefineVariant.
Restricting Values
A golem struct tag restricts a field, on a method's parameters or on a record. The restriction is published in the schema, and the platform rejects a value outside it before the method runs:
- Numbers take
min,maxandunit. A quantity takesminandmax, such as0.5in its base unit or20kg. golem.Texttakeslanguages,minLength,maxLengthandregex. A plainstringcarries no restrictions.golem.Binarytakesmime,minBytesandmaxBytes.golem.Pathtakesdirection,kind,mimeandextensions.golem.URLtakesschemesandhosts.- Lists are separated by
|. Aregexruns to the end of the tag, so put it last. - A tag that does not fit the field's type is reported as a definition error.
Returning Failures
Handlers return only their output value. Signal failure two ways:
- Uncaught errors — a
panic(e.g. fromgolem.Must(...)on an unexpected error) traps the component, as in Rust: the invocation fails without retry and the caller gets an error, not a result. - Domain errors the caller should observe as a value — model them in the method's output type with
golem.Result[Ok, Err]:
In agents/counter/impl/impl.go, using the counter import, agent and state defined above, register the handler in init:
Returning golem.Err(...) completes the invocation successfully — the caller receives the error as a value (and can unwrap with .MustOk()). Panicking instead fails the whole agent.
Key Constraints
- Method parameters/results are passed by value; wrap the parameter list in a struct (one field per WIT parameter).
- A
golem.Principalfield in a method's input struct (or theID) is filled by the host with the invocation's principal and is not a parameter callers pass;ctx.Principal()is the principal the agent was initialized with (seegolem-add-http-auth-go). IDmust be a struct; its fields plus an optional phantom UUID define identity. Durable agents are created implicitly on first invocation. An emptyID(type ID struct{}) is a singleton only for non-phantom durable addressing.NewPhantomadds a fresh UUID without changing the mode; ephemeral targets require phantom addressing. Use a newNewPhantomtarget for each independent ephemeral call; do not reuse a completed ephemeral target (seegolem-multi-instance-agent-go).- An agent admits invocations sequentially, but goroutines within one invocation can interleave at yield points (for example, while waiting for RPC, HTTP, streams or promises). This is cooperative concurrency, not a promise of CPU-thread parallelism. Synchronize shared mutable state when goroutines can interleave; sequential invocation admission does not remove that need.
- Method descriptors must be package-level vars in the definition package (the same value is used by the schema, the binding, and callers).
- State lives only in the impl package (unexported) — callers never see it.
- Target is WASM only: no raw sockets; outgoing HTTP goes through the SDK's WASI transport (see
golem-make-http-request-go).
Related Skills
| Skill | When to Load | |
|---|---|---|
golem-call-another-agent-go | This agent needs to call another agent (RPC) | |
golem-add-http-endpoint-go | Expose this agent's methods over HTTP | |
golem-multi-instance-agent-go | Address many instances of an agent by ID | |
golem-custom-snapshot-go | Customize how the agent's state is snapshotted |
Security
- Security scanPassed, 90 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckinggolem-skills/skills/go/golem-add-agent-go/SKILL.md
Popularity
- 7-day trend score
- 0
Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/golemcloud/golem/golem-add-agent-go)