Documentation
¶
Overview ¶
Package hermesacp exposes the local Hermes CLI as an Agent Client Protocol agent.
Most hosts run the agent over a pair of JSON-RPC streams using Serve. Serve launches one authenticated loopback `hermes serve` process per ACP session, maps ACP requests into native gateway WebSocket JSON-RPC calls, and streams gateway events back to the client as ACP session updates. Without a HostAuthority, native processes run under the adapter's ordinary same-identity launcher. WithHostAuthority routes every native launch and prepared tree through the supplied authority. A cancelled or timed-out session lazily resumes its exact native key from the last committed snapshot on the next prompt. Hosts must complete ACP initialization before issuing session or other agent methods.
Hosts should use Serve for the JSON-RPC transport; hosts that embed the agent directly construct one with NewAgent and the same Option values, plus WithClient to supply the ACP client the agent streams session updates, permission requests, and elicitations to. Serve installs the connection it builds as that client and refuses an option set carrying one. A direct prompt error caused by gateway loss matches ErrGatewayDisconnected and retains its exact native cause; Serve converts that chain to bounded, secret-safe ACP error data at the wire boundary. Hermes authentication and provider credentials remain owned by native Hermes. Each session runs under its own ephemeral `HERMES_HOME` materialized beneath the scratch parent from WithScratchDir. WithSharedHermesHome explicitly opts official Hermes into one durable native home shared by this adapter's otherwise independent per-session processes; the adapter claims that home root exclusively and a second adapter is refused it. Provider OAuth additionally requires WithProviderAuthRoot for values-free connection lineage, and enabling it canonicalizes the shared home: the adapter creates it 0700, resolves its symlinks, and uses the resolved path as HERMES_HOME. A login leg also requires the per-process browser-launcher shim and refuses before any native call without it. The adapter never reads or copies credentials. WithHome remains unsupported.
Prompt images arrive either as embedded base64 or, for a co-located host that sets WithInputHandoffRoot, as digest-verified files under that read-only root. The adapter enforces the same gates on both transports and advertises the bounds it enforces at initialize; the handoff root is read-only, so it materializes nothing and WithScratchDir remains the only source of ephemeral on-disk state.
Hosts that need durable remote resume can provide WithSessionStore. A session store receives `hermes-state-db-v1` snapshots keyed by the ACP-visible session ID and subpath, can back session/list, and can hydrate a snapshot into a fresh per-session Hermes home for session/load or session/resume when isolated native state is absent. Shared-home mode stores logical metadata only and resumes against the durable official database.
Hosts can call CallForkSession for the Hermes fork extension method _hermes/session/fork. Raw Hermes gateway events are emitted as RawEventMethod notifications only when a session request opts in with WithSessionRawEvents.
Hosts that need adapter telemetry can provide OpenTelemetry providers with WithTracerProvider and WithMeterProvider. The package never configures global OpenTelemetry providers; the acp-go-hermes binary handles env-based exporter setup for command-line use. Caller-supplied providers remain owned by the caller, including ForceFlush and Shutdown.
Index ¶
- Constants
- Variables
- func CallForkSession(ctx context.Context, conn *acp.ClientSideConnection, ...) (acp.UnstableForkSessionResponse, error)
- func CancelRequest(sessionID acp.SessionId, turnNonce string) acp.CancelNotification
- func DeleteSessionRequest(sessionID acp.SessionId) acp.UnstableDeleteSessionRequest
- func ForkSessionRequest(sessionID acp.SessionId, cwd string, opts ...SessionRequestOption) acp.UnstableForkSessionRequest
- func HTTPMCPServer(name string, url string, headers map[string]string) acp.McpServer
- func ListSessionsRequest(opts ...ListSessionsRequestOption) acp.ListSessionsRequest
- func LoadSessionRequest(sessionID acp.SessionId, cwd string, opts ...SessionRequestOption) acp.LoadSessionRequest
- func NewSessionRequest(cwd string, opts ...SessionRequestOption) acp.NewSessionRequest
- func PromptRequest(sessionID acp.SessionId, turnNonce string, blocks ...acp.ContentBlock) acp.PromptRequest
- func ResumeSessionRequest(sessionID acp.SessionId, cwd string, opts ...SessionRequestOption) acp.ResumeSessionRequest
- func Serve(ctx context.Context, input io.Reader, output io.Writer, opts ...Option) (returnErr error)
- func SetConfigOptionRequest(sessionID acp.SessionId, configID acp.SessionConfigId, ...) acp.SetSessionConfigOptionRequest
- func SetModelRequest(sessionID acp.SessionId, model string) acp.SetSessionConfigOptionRequest
- func StdioMCPServer(name string, command string, args []string, env map[string]string) acp.McpServer
- func TextPromptRequest(sessionID acp.SessionId, turnNonce, text string) acp.PromptRequest
- type Agent
- func (a *Agent) Authenticate(_ context.Context, params acp.AuthenticateRequest) (acp.AuthenticateResponse, error)
- func (a *Agent) Cancel(ctx context.Context, params acp.CancelNotification) error
- func (a *Agent) Close() error
- func (a *Agent) CloseSession(ctx context.Context, params acp.CloseSessionRequest) (acp.CloseSessionResponse, error)
- func (a *Agent) HandleExtensionMethod(ctx context.Context, method string, params json.RawMessage) (any, error)
- func (a *Agent) Initialize(_ context.Context, params acp.InitializeRequest) (acp.InitializeResponse, error)
- func (a *Agent) ListSessions(ctx context.Context, params acp.ListSessionsRequest) (acp.ListSessionsResponse, error)
- func (a *Agent) LoadSession(ctx context.Context, params acp.LoadSessionRequest) (acp.LoadSessionResponse, error)
- func (a *Agent) Logout(_ context.Context, params acp.LogoutRequest) (acp.LogoutResponse, error)
- func (a *Agent) NewSession(ctx context.Context, params acp.NewSessionRequest) (_ acp.NewSessionResponse, returnErr error)
- func (a *Agent) Prompt(ctx context.Context, params acp.PromptRequest) (resp acp.PromptResponse, err error)
- func (a *Agent) ResumeSession(ctx context.Context, params acp.ResumeSessionRequest) (acp.ResumeSessionResponse, error)
- func (a *Agent) SetSessionConfigOption(ctx context.Context, params acp.SetSessionConfigOptionRequest) (acp.SetSessionConfigOptionResponse, error)
- func (a *Agent) SetSessionMode(_ context.Context, params acp.SetSessionModeRequest) (acp.SetSessionModeResponse, error)
- func (a *Agent) UnstableDeleteSession(ctx context.Context, params acp.UnstableDeleteSessionRequest) (acp.UnstableDeleteSessionResponse, error)
- type ConcurrencyLimits
- type ExtensionNotificationHandler
- type HermesOption
- type HermesOptions
- type HostAuthority
- type ImageLimits
- type InMemorySessionStore
- func (s *InMemorySessionStore) Append(ctx context.Context, key SessionKey, entries []SessionStoreEntry) error
- func (s *InMemorySessionStore) Delete(ctx context.Context, key SessionKey) error
- func (s *InMemorySessionStore) ListSessions(ctx context.Context) ([]SessionSummary, error)
- func (s *InMemorySessionStore) ListSubkeys(ctx context.Context, key SessionKey) ([]string, error)
- func (s *InMemorySessionStore) Load(ctx context.Context, key SessionKey) ([]SessionStoreEntry, error)
- func (s *InMemorySessionStore) Replace(ctx context.Context, main SessionKey, replacements []SessionStoreReplacement) error
- type ListSessionsRequestOption
- type NativeProcess
- type NativeRequest
- type NativeResult
- type Option
- func WithAgentName(name string) Option
- func WithAgentTitle(title string) Option
- func WithAgentVersion(version string) Option
- func WithClient(client acp.Client) Option
- func WithConcurrencyLimits(limits ConcurrencyLimits) Option
- func WithDefaultModel(model string) Option
- func WithEnv(env map[string]string) Option
- func WithExecutablePath(path string) Option
- func WithHome(path string) Option
- func WithHostAuthority(authority HostAuthority) Option
- func WithImageLimits(limits ImageLimits) Option
- func WithInputHandoffRoot(dir string) Option
- func WithLogger(logger *slog.Logger) Option
- func WithMeterProvider(provider metric.MeterProvider) Option
- func WithProviderAuthRoot(path string) Option
- func WithScratchDir(dir string) Option
- func WithSeedFiles(files map[string]string) Option
- func WithSessionStore(store SessionStore) Option
- func WithSessionStoreLoadTimeout(timeout time.Duration) Option
- func WithSharedHermesHome(path string) Option
- func WithTextMapPropagator(propagator propagation.TextMapPropagator) Option
- func WithTracerProvider(provider trace.TracerProvider) Option
- func WithTurnTimeout(timeout time.Duration) Option
- type Options
- type SessionKey
- type SessionRequestOption
- func WithSessionAdditionalDirectories(paths ...string) SessionRequestOption
- func WithSessionHermesOptions(options HermesOptions) SessionRequestOption
- func WithSessionMCPServers(servers ...acp.McpServer) SessionRequestOption
- func WithSessionMeta(meta map[string]any) SessionRequestOption
- func WithSessionOutputSchema(schema map[string]any) SessionRequestOption
- func WithSessionRawEvents(enabled bool) SessionRequestOption
- type SessionStore
- type SessionStoreEntry
- type SessionStoreReplacement
- type SessionStoreTerminalState
- type SessionSummary
Examples ¶
Constants ¶
const ( AuthMethodsMethod = "_hermes/auth/methods" AuthAuthorizeMethod = "_hermes/auth/authorize" AuthCallbackMethod = "_hermes/auth/callback" AuthStatusMethod = "_hermes/auth/status" AuthCancelMethod = "_hermes/auth/cancel" AuthInventoryMethod = "_hermes/auth/inventory" AuthDisconnectMethod = "_hermes/auth/disconnect" )
Session-scoped provider-auth extension methods. Hermes owns credential material in the configured native auth home; this surface coordinates only values-free flow and lineage state.
const ( ForkSessionMethod = "_hermes/session/fork" RawEventMethod = "_hermes/rawEvent" )
const ( SessionStoreMainSubpath = "" SessionStoreFormat = "hermes-state-db-v1" )
Variables ¶
var ( ErrHostAuthorityUnavailable = errors.New("host authority unavailable") // ErrContainmentIncomplete reports that native process containment is uncertain. ErrContainmentIncomplete = errors.New("native containment incomplete") // ErrNativeTreeBusy reports a non-mutating reclaim refusal while lease processes remain. ErrNativeTreeBusy = errors.New("native tree has live lease processes") )
var ( ErrSessionOperationAmbiguous = errors.New("hermes session-operation recovery is ambiguous") )
var ErrGatewayDisconnected = nativehermes.ErrGatewayDisconnected
ErrGatewayDisconnected classifies loss of the Hermes gateway while retaining the exact native transport cause in the returned error chain.
var ErrSessionPumpOverflow = errors.New("hermes session actor mailbox overflow")
Functions ¶
func CallForkSession ¶
func CallForkSession(ctx context.Context, conn *acp.ClientSideConnection, params acp.UnstableForkSessionRequest) (acp.UnstableForkSessionResponse, error)
func CancelRequest ¶
func CancelRequest(sessionID acp.SessionId, turnNonce string) acp.CancelNotification
CancelRequest builds an active-turn cancellation carrying the mandatory route nonce.
func DeleteSessionRequest ¶
func DeleteSessionRequest(sessionID acp.SessionId) acp.UnstableDeleteSessionRequest
func ForkSessionRequest ¶
func ForkSessionRequest(sessionID acp.SessionId, cwd string, opts ...SessionRequestOption) acp.UnstableForkSessionRequest
func HTTPMCPServer ¶
func ListSessionsRequest ¶
func ListSessionsRequest(opts ...ListSessionsRequestOption) acp.ListSessionsRequest
func LoadSessionRequest ¶
func LoadSessionRequest(sessionID acp.SessionId, cwd string, opts ...SessionRequestOption) acp.LoadSessionRequest
func NewSessionRequest ¶
func NewSessionRequest(cwd string, opts ...SessionRequestOption) acp.NewSessionRequest
func PromptRequest ¶
func PromptRequest(sessionID acp.SessionId, turnNonce string, blocks ...acp.ContentBlock) acp.PromptRequest
func ResumeSessionRequest ¶
func ResumeSessionRequest(sessionID acp.SessionId, cwd string, opts ...SessionRequestOption) acp.ResumeSessionRequest
func Serve ¶
func Serve(ctx context.Context, input io.Reader, output io.Writer, opts ...Option) (returnErr error)
Example (Initialize) ¶
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
clientToAgentReader, clientToAgentWriter := io.Pipe()
agentToClientReader, agentToClientWriter := io.Pipe()
defer clientToAgentReader.Close()
defer clientToAgentWriter.Close()
defer agentToClientReader.Close()
defer agentToClientWriter.Close()
done := make(chan error, 1)
go func() {
done <- Serve(ctx, clientToAgentReader, agentToClientWriter)
}()
_, _ = fmt.Fprintln(clientToAgentWriter, `{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":1}}`)
line, _ := bufio.NewReader(agentToClientReader).ReadString('\n')
cancel()
_ = clientToAgentWriter.Close()
<-done
var response struct {
Result struct {
AuthMethods []any `json:"authMethods"`
AgentCapabilities struct {
LoadSession bool `json:"loadSession"`
McpCapabilities struct {
Http bool `json:"http"`
} `json:"mcpCapabilities"`
} `json:"agentCapabilities"`
} `json:"result"`
}
_ = json.Unmarshal([]byte(line), &response)
fmt.Println(len(response.Result.AuthMethods) == 0)
fmt.Println(response.Result.AgentCapabilities.LoadSession)
fmt.Println(response.Result.AgentCapabilities.McpCapabilities.Http)
Output: true true true
func SetConfigOptionRequest ¶
func SetConfigOptionRequest(sessionID acp.SessionId, configID acp.SessionConfigId, value acp.SessionConfigValueId) acp.SetSessionConfigOptionRequest
func SetModelRequest ¶
func SetModelRequest(sessionID acp.SessionId, model string) acp.SetSessionConfigOptionRequest
func StdioMCPServer ¶
func TextPromptRequest ¶
func TextPromptRequest(sessionID acp.SessionId, turnNonce, text string) acp.PromptRequest
Types ¶
type Agent ¶
type Agent struct {
// contains filtered or unexported fields
}
Agent exposes Hermes through ACP.
func (*Agent) Authenticate ¶
func (a *Agent) Authenticate(_ context.Context, params acp.AuthenticateRequest) (acp.AuthenticateResponse, error)
Authenticate advertises no method, so every call is refused. The reserved lifecycle literal is inspected first: a request naming a key this surface never carries is malformed before it is unauthenticated.
func (*Agent) CloseSession ¶
func (a *Agent) CloseSession(ctx context.Context, params acp.CloseSessionRequest) (acp.CloseSessionResponse, error)
func (*Agent) HandleExtensionMethod ¶
func (*Agent) Initialize ¶
func (a *Agent) Initialize(_ context.Context, params acp.InitializeRequest) (acp.InitializeResponse, error)
func (*Agent) ListSessions ¶
func (a *Agent) ListSessions(ctx context.Context, params acp.ListSessionsRequest) (acp.ListSessionsResponse, error)
func (*Agent) LoadSession ¶
func (a *Agent) LoadSession(ctx context.Context, params acp.LoadSessionRequest) (acp.LoadSessionResponse, error)
func (*Agent) Logout ¶
func (a *Agent) Logout(_ context.Context, params acp.LogoutRequest) (acp.LogoutResponse, error)
func (*Agent) NewSession ¶
func (a *Agent) NewSession(ctx context.Context, params acp.NewSessionRequest) (_ acp.NewSessionResponse, returnErr error)
func (*Agent) Prompt ¶
func (a *Agent) Prompt(ctx context.Context, params acp.PromptRequest) (resp acp.PromptResponse, err error)
func (*Agent) ResumeSession ¶
func (a *Agent) ResumeSession(ctx context.Context, params acp.ResumeSessionRequest) (acp.ResumeSessionResponse, error)
func (*Agent) SetSessionConfigOption ¶
func (a *Agent) SetSessionConfigOption(ctx context.Context, params acp.SetSessionConfigOptionRequest) (acp.SetSessionConfigOptionResponse, error)
func (*Agent) SetSessionMode ¶
func (a *Agent) SetSessionMode(_ context.Context, params acp.SetSessionModeRequest) (acp.SetSessionModeResponse, error)
SetSessionMode carries no native mode surface, so it answers method-not-found. The lifecycle refusal still precedes that answer, for the same reason Authenticate's does.
func (*Agent) UnstableDeleteSession ¶
func (a *Agent) UnstableDeleteSession(ctx context.Context, params acp.UnstableDeleteSessionRequest) (acp.UnstableDeleteSessionResponse, error)
type ConcurrencyLimits ¶
ConcurrencyLimits bounds work accepted by one Agent.
type ExtensionNotificationHandler ¶
type ExtensionNotificationHandler interface {
ExtensionNotification(ctx context.Context, method string, params any) error
}
ExtensionNotificationHandler is the optional client surface that receives the agent's namespaced extension notifications. A directly embedded client that implements it receives RawEventMethod exactly as a JSON-RPC peer does; one that does not is never sent them.
type HermesOption ¶
type HermesOption func(*HermesOptions)
func WithHermesEnv ¶
func WithHermesEnv(env map[string]string) HermesOption
func WithHermesExtraPathDirs ¶
func WithHermesExtraPathDirs(dirs ...string) HermesOption
WithHermesExtraPathDirs configures absolute directories placed, in order, ahead of the native base PATH for this session's Hermes process and terminal commands. Session Env cannot carry PATH, BASH_ENV, or the adapter's private carrier namespace; this ordered option is the sole session PATH authority.
func WithHermesModel ¶
func WithHermesModel(model string) HermesOption
func WithHermesOutputSchema ¶
func WithHermesOutputSchema(schema map[string]any) HermesOption
type HermesOptions ¶
type HermesOptions struct {
Model string `json:"model,omitempty"`
Env map[string]string `json:"env,omitempty"`
ExtraPathDirs []string `json:"extraPathDirs,omitempty"`
OutputSchema map[string]any `json:"outputSchema,omitempty"`
}
HermesOptions is the stable Hermes-specific subset accepted at _meta.hermes.options.
func NewHermesOptions ¶
func NewHermesOptions(opts ...HermesOption) HermesOptions
func (HermesOptions) Meta ¶
func (options HermesOptions) Meta() map[string]any
Meta returns an ACP _meta object for the supported Hermes-specific options.
type HostAuthority ¶
type HostAuthority interface {
NativeEnvironment() map[string]string
PrepareNativeTree(context.Context, string) error
ReadNativeAppendLog(context.Context, string, uint64) ([][]byte, error)
WriteNativeAppendLog(context.Context, string, [][]byte) error
ReclaimNativeTree(context.Context, string) error
StartNative(context.Context, NativeRequest) (NativeProcess, error)
}
HostAuthority owns native process execution and prepared-tree transitions.
type ImageLimits ¶
type ImageLimits struct {
MaxInputBytesPerImage int64
MaxInputBytesPerPrompt int64
MaxOutputBytesPerImage int64
MaxOutputBytesPerToolCall int64
}
ImageLimits bounds decoded image bytes. Every field counts decoded bytes, never base64 characters or enclosing JSON, and defaults to 6 MiB decoded (6,291,456 bytes). A field explicitly set to zero in a supplied ImageLimits disables that adapter policy limit; it never bypasses native framing, provider, memory, or host request limits. Negative fields are rejected at agent construction. The two output fields are accepted for the uniform option surface; this adapter emits no typed image output, so no output limit is ever consulted.
type InMemorySessionStore ¶
type InMemorySessionStore struct {
// contains filtered or unexported fields
}
func NewInMemorySessionStore ¶
func NewInMemorySessionStore() *InMemorySessionStore
func (*InMemorySessionStore) Append ¶
func (s *InMemorySessionStore) Append(ctx context.Context, key SessionKey, entries []SessionStoreEntry) error
func (*InMemorySessionStore) Delete ¶
func (s *InMemorySessionStore) Delete(ctx context.Context, key SessionKey) error
func (*InMemorySessionStore) ListSessions ¶
func (s *InMemorySessionStore) ListSessions(ctx context.Context) ([]SessionSummary, error)
func (*InMemorySessionStore) ListSubkeys ¶
func (s *InMemorySessionStore) ListSubkeys(ctx context.Context, key SessionKey) ([]string, error)
func (*InMemorySessionStore) Load ¶
func (s *InMemorySessionStore) Load(ctx context.Context, key SessionKey) ([]SessionStoreEntry, error)
func (*InMemorySessionStore) Replace ¶
func (s *InMemorySessionStore) Replace(ctx context.Context, main SessionKey, replacements []SessionStoreReplacement) error
type ListSessionsRequestOption ¶
type ListSessionsRequestOption func(*acp.ListSessionsRequest)
func WithListSessionsCursor ¶
func WithListSessionsCursor(cursor string) ListSessionsRequestOption
func WithListSessionsCwd ¶
func WithListSessionsCwd(cwd string) ListSessionsRequestOption
func WithListSessionsMeta ¶
func WithListSessionsMeta(meta map[string]any) ListSessionsRequestOption
WithListSessionsMeta merges host-supplied metadata into a `session/list` request's `_meta`, on the same reserved-namespace terms as WithSessionMeta.
type NativeProcess ¶
type NativeProcess interface {
Stdin() io.WriteCloser
Stdout() io.ReadCloser
Stderr() io.ReadCloser
Wait(context.Context) (NativeResult, error)
Revoke(context.Context) error
}
NativeProcess is a host-owned native process with revocation and terminal observation.
type NativeRequest ¶
type NativeRequest struct {
Executable string
Arguments []string
Environment []string
WorkingDirectory string
}
NativeRequest describes one host-authorized native process launch.
type NativeResult ¶
NativeResult describes a terminal native process.
type Option ¶
type Option func(*Options)
Option configures the Hermes ACP agent.
func WithAgentName ¶
func WithAgentTitle ¶
func WithAgentVersion ¶
func WithClient ¶
WithClient supplies the ACP client a directly constructed Agent streams to.
Serve builds a JSON-RPC connection and installs it as the agent's client, so a host that runs the agent over stdio never sets this. A host that embeds the Agent and calls its ACP methods in-process gets the same outbound surface only through this option: session updates, permission requests, and elicitations are agent-to-client traffic, and an Agent with no client cannot deliver them. The supplied client is called from the agent's own goroutines and must be safe for concurrent use.
Elicitation is delivered only when the client also implements UnstableCreateElicitation (the SDK's ClientExperimental surface); a client without it refuses elicitations instead of dropping them. Extension notifications, including RawEventMethod, are delivered only when the client implements ExtensionNotificationHandler.
func WithConcurrencyLimits ¶
func WithConcurrencyLimits(limits ConcurrencyLimits) Option
func WithDefaultModel ¶
func WithEnv ¶
WithEnv supplies the static Agent-scoped native environment overlay. BASH_ENV and ACP_GO_HERMES_PATH_DIR_* are reserved for the adapter's native terminal PATH carrier and fail Agent construction.
func WithExecutablePath ¶
func WithHome ¶
WithHome is unsupported because native residence selection is explicit. Use WithScratchDir for isolated ephemeral state or WithSharedHermesHome for the official-Hermes shared durable mode.
func WithHostAuthority ¶
func WithHostAuthority(authority HostAuthority) Option
WithHostAuthority routes native processes and tree ownership through authority.
func WithImageLimits ¶
func WithImageLimits(limits ImageLimits) Option
WithImageLimits replaces every decoded-byte image limit with the supplied values. A zero field disables that adapter policy limit; a negative field is rejected at agent construction. Omitting the option leaves all four fields at their default of 6 MiB decoded.
func WithInputHandoffRoot ¶
WithInputHandoffRoot sets the read-only root under which the host has materialized handoff image files, enabling the local-handoff prompt form: an image block with empty data, a file URI under this root, and an acp-go.dev/handoff envelope carrying the file's sha256 digest and size. The path must be absolute; a relative path is rejected at agent construction. Omitting the option leaves the form rejected as invalid_handoff, and the acp-go.dev/handoff capability is then not advertised. Files under the root stay host-owned: the adapter resolves, reads, and verifies them, and never writes, moves, or removes anything there.
func WithLogger ¶
func WithMeterProvider ¶
func WithMeterProvider(provider metric.MeterProvider) Option
func WithProviderAuthRoot ¶
WithProviderAuthRoot sets the durable directory that houses the values-free provider-auth ledger. The directory is created 0700 when missing and ledger entries are written 0600. Provider auth is enabled only when WithSharedHermesHome is also set. The root carries no config or auth-resolution semantics and is never a scratch parent.
Three wrong configurations answer differently. Omitting this option leaves every provider-auth method unadvertised and answering method-not-found: a leg that cannot record what it did is never offered. A relative root, or this option without WithSharedHermesHome, is a construction failure that every Initialize reports as an internal error. An absolute root the agent cannot prepare — one it cannot create, restrict to 0700, or confirm as a writable directory — is logged at warn level and leaves the surface unadvertised while the rest of the agent works.
func WithScratchDir ¶
WithScratchDir sets the sole parent directory for all ephemeral on-disk materialization: isolated per-session Hermes homes, sqlite temp directories, and process/server temp roots. An empty value (the default) means the system temp directory. The directory is created with 0700 permissions when missing.
func WithSeedFiles ¶
WithSeedFiles maps relative paths to file contents that the adapter writes into each session's isolated Hermes config root before launching hermes, so hermes reads them as its own config (for example config.yaml). Paths are confined to that root: absolute paths, ".." segments, and empty keys are rejected at session start. Contents are written verbatim, so secrets belong in WithEnv and are referenced from seeded files by env-var indirection (for example hermes key_env), never written into a seeded file.
func WithSessionStore ¶
func WithSessionStore(store SessionStore) Option
func WithSharedHermesHome ¶
WithSharedHermesHome explicitly selects official shared-home mode: every native gateway uses path as its exact durable HERMES_HOME. This intentionally gives up per-session Hermes-home isolation so credentials and native sessions survive adapter restarts with the official runtime.
The path must be absolute and already clean, and requires ordinary same-identity execution. Provider-auth extension methods additionally require WithProviderAuthRoot, and configuring both canonicalizes this path: the agent creates the directory 0700 when absent, resolves its symlinks, and adopts the resolved path for the rest of its life. That resolved path — not the spelling passed here — is the HERMES_HOME and shared XDG root every native process receives, the root the exclusive home-root claim fences, and the value the ledger's per-home key hashes, so a caller that named the home through a symlink must compare against the resolved form. Without WithProviderAuthRoot the path is used verbatim. Each ACP session retains its own native process, environment, PATH additions, event stream, and adapter-owned control generation. Native database and auth state are intentionally shared through path. Managed MCP configuration must be identical for every session owned by the Agent.
func WithTextMapPropagator ¶
func WithTextMapPropagator(propagator propagation.TextMapPropagator) Option
func WithTracerProvider ¶
func WithTracerProvider(provider trace.TracerProvider) Option
func WithTurnTimeout ¶
WithTurnTimeout bounds how long a single native turn may run before the wrapper interrupts it, closes and proves the whole native process boundary, and fails the prompt with a hermes_turn_failed error whose cause is "timeout". The default of 0 disables the deadline. A timeout is a failure, not a user cancel, so it is never reported as StopReason cancelled.
type Options ¶
type Options struct {
AgentName string
AgentTitle string
AgentVersion string
ExecutablePath string
HostAuthority HostAuthority
// Home is unsupported because native residence selection is explicit. Use
// ScratchDir for isolated ephemeral state or SharedHermesHome for the
// official-Hermes shared durable mode.
Home string
// ScratchDir is the sole parent directory for all ephemeral on-disk
// materialization: isolated per-session Hermes homes, sqlite temp
// directories, and process/server temp roots. An empty value means the
// system temp directory. It is created with 0700 permissions when missing.
ScratchDir string
// InputHandoffRoot is the read-only root under which the host materializes
// handoff image files. An empty value (the default) leaves the local-handoff
// prompt form rejected. It is not a materialization option: the adapter
// never writes, moves, or removes anything under it.
InputHandoffRoot string
// ProviderAuthRoot is the absolute, host-owned, durable directory that
// houses the values-free provider-auth ledger. It is not ephemeral
// materialization: the ledger deliberately outlives every session and every
// native generation, which is the one class of state a scratch parent must
// not hold. Provider auth is enabled only when SharedHermesHome is also set.
ProviderAuthRoot string
// SharedHermesHome selects official shared-home mode. Every native
// process uses this one durable home, so per-session Hermes-home isolation is
// intentionally disabled. Per-session processes and adapter-owned control
// generations remain independent. When ProviderAuthRoot is also set, NewAgent
// replaces this field with the symlink-resolved residence it prepared, and
// that resolved path is what every native process and every home-keyed claim
// then uses.
DefaultModel string
Env map[string]string
Logger *slog.Logger
TracerProvider trace.TracerProvider
MeterProvider metric.MeterProvider
TextMapPropagator propagation.TextMapPropagator
// Client is the ACP client an embedded agent streams to. It is set by
// WithClient and is the embedding host's counterpart to the JSON-RPC
// transport Serve builds: without it a directly constructed Agent has
// nowhere to publish session updates, permission requests, or
// elicitations. Serve refuses an Options carrying one, because Serve
// installs the connection it owns.
Client acp.Client
SessionStore SessionStore
SessionStoreLoadTimeout time.Duration
ConcurrencyLimits ConcurrencyLimits
ImageLimits ImageLimits
SeedFiles map[string]string
TurnTimeout time.Duration
// contains filtered or unexported fields
}
Options configures the ACP agent process and Hermes sessions it starts.
type SessionKey ¶
type SessionRequestOption ¶
type SessionRequestOption func(*sessionRequestConfig)
func WithSessionAdditionalDirectories ¶
func WithSessionAdditionalDirectories(paths ...string) SessionRequestOption
func WithSessionHermesOptions ¶
func WithSessionHermesOptions(options HermesOptions) SessionRequestOption
func WithSessionMCPServers ¶
func WithSessionMCPServers(servers ...acp.McpServer) SessionRequestOption
func WithSessionMeta ¶
func WithSessionMeta(meta map[string]any) SessionRequestOption
WithSessionMeta merges host-supplied metadata into a session lifecycle request's `_meta`. The `acp-go.dev/*` namespace is family-global and reserved: its envelopes are stamped by this package and read by every sibling, so a caller key inside it is refused rather than merged or overwritten. A merged one would put a host's value where a reader expects a family envelope; an overwritten one would silently discard what the host asked for. Neither is a request this builder can honestly produce, and there is no return value to carry the refusal, so it panics — the caller is a program naming a namespace that is not its own.
func WithSessionOutputSchema ¶
func WithSessionOutputSchema(schema map[string]any) SessionRequestOption
func WithSessionRawEvents ¶
func WithSessionRawEvents(enabled bool) SessionRequestOption
type SessionStore ¶
type SessionStore interface {
Append(ctx context.Context, key SessionKey, entries []SessionStoreEntry) error
Load(ctx context.Context, key SessionKey) ([]SessionStoreEntry, error)
Replace(ctx context.Context, main SessionKey, replacements []SessionStoreReplacement) error
Delete(ctx context.Context, key SessionKey) error
ListSessions(ctx context.Context) ([]SessionSummary, error)
ListSubkeys(ctx context.Context, key SessionKey) ([]string, error)
}
type SessionStoreEntry ¶
type SessionStoreEntry = json.RawMessage
type SessionStoreReplacement ¶
type SessionStoreReplacement struct {
Key SessionKey
Entries []SessionStoreEntry
}
type SessionStoreTerminalState ¶
SessionStoreTerminalState is the durable foreground boundary of one committed hermes-state-db-v1 main snapshot: the terminal assistant identity the native archive holds, and the truthful outcome the wrapper recorded for the last accepted turn.
MessageID is empty until a turn completes a finished assistant row. Outcome and StopReason are empty until an accepted turn settles; StopReason stays empty when Outcome is `failed`, because no ACP v1 stop reason names a failure.
func InspectSessionStoreTerminalState ¶
func InspectSessionStoreTerminalState( logicalSessionID string, entries []SessionStoreEntry, ) (SessionStoreTerminalState, error)
InspectSessionStoreTerminalState validates exactly one current-format main snapshot for logicalSessionID and returns its latest finished assistant identity. A valid session that has not completed an assistant turn returns the zero state. Missing terminal summaries and snapshots from any other format are rejected.
Source Files
¶
- absolute_path_spelling_unix.go
- agent.go
- agent_connection.go
- agent_embedded_client.go
- agent_environment.go
- agent_goroutine.go
- agent_host_authority.go
- agent_lifecycle.go
- agent_lifecycle_open.go
- agent_route.go
- agent_session.go
- agent_session_lifecycle.go
- auth.go
- auth_admission.go
- auth_catalog.go
- auth_disconnect.go
- auth_flow_failures.go
- auth_flows.go
- auth_ledger.go
- auth_ledger_sync_unix.go
- auth_provider_lock.go
- auth_provider_lock_unix.go
- doc.go
- host_authority.go
- ids.go
- image_handoff.go
- image_handoff_unix.go
- image_input.go
- image_media_envelope.go
- managed_hermes_server.go
- options.go
- raw_events.go
- request_builders.go
- scratch.go
- session.go
- session_config.go
- session_lifecycle_stream.go
- session_meta.go
- session_operation_journal.go
- session_operation_recovery.go
- session_operation_sync_unix.go
- session_prompt.go
- session_pump.go
- session_settlement.go
- session_state_store.go
- session_store.go
- session_store_decode.go
- session_store_terminal.go
- session_validation.go
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
acp-go-hermes
command
|
|
|
examples
|
|
|
interactive-chat
command
|
|
|
minimal-client
command
|
|
|
resume-from-file
command
|
|
|
internal
|
|
|
lifecycle
Package lifecycle implements the `acp-go.dev/lifecycle` extension: the closed event vocabulary, the strict wire decoder, and the reducer that validates one ordered session lifecycle stream.
|
Package lifecycle implements the `acp-go.dev/lifecycle` extension: the closed event vocabulary, the strict wire decoder, and the reducer that validates one ordered session lifecycle stream. |