Use the Runtime facade when your Go application needs direct lifecycle, authorization, or event control. Use the generic Server when an authenticated loopback HTTP/SSE boundary is sufficient.
package main
import (
"context"
"errors"
"log"
"os"
"os/signal"
agentruntime "github.com/colinagent/opagent/opagent-runtime/runtime"
)
func main() {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
rt, err := agentruntime.New(agentruntime.Options{})
if err != nil {
log.Fatal(err)
}
defer rt.Close(context.Background())
if err := rt.Run(ctx); err != nil && !errors.Is(err, context.Canceled) {
log.Fatal(err)
}
}Production hosts may add platform-specific termination signals when appropriate.
Set only the hooks your host owns. For example, an allowlist for a remote node should compare a normalized URL and node identity loaded from trusted host configuration. Do not derive authorization from the same manifest or request being authorized.
rt, err := agentruntime.New(agentruntime.Options{
BaseDir: "/srv/my-host/opagent",
RemoteNodeAuthorizer: func(ctx context.Context, node *op.OpNode) error {
if !trustedRemoteNode(node) {
return errors.New("remote node is not trusted")
}
return nil
},
})Background services receive Runtime's lifecycle context. They must return when it is cancelled and must not start independent immortal goroutines.
- Start
Runand wait forReady. - Create a thread with
HandleNode(thread/create). - Subscribe before submitting if every live event matters to the host UI.
- Submit with
HandleNode(thread/submit)and an explicitmodelKey. - Rebuild durable state from thread snapshots, not from an assumed lossless event subscription.
- Cancel a specific turn with
HandleAgent(thread/interrupted); callCloseto stop the Runtime.
For a tested implementation of this flow, read
opagent-server/server.