Embedding Abhed

Status: 2026-09-06

Everything Abhed does lives under internal/, which Go refuses to let another module import. That is right for a binary and a wall for anyone who wants the agent inside their own service. The sdk package is the supported surface across that wall, kept small so the internals stay free to change.

import abhed "github.com/yuvrajsingh/abhed/sdk"

a, err := abhed.New(ctx, abhed.Options{
    Workspace: "/srv/work",
    Provider: &abhed.Provider{
        Type: "anthropic", Model: "claude-opus-5",
        APIKey: os.Getenv("ANTHROPIC_API_KEY"),
    },
    Mode: "auto",
    Deny: []string{"bash(rm -rf *)"},
    Approve: func(ctx context.Context, tool string, args json.RawMessage, d abhed.Decision) (bool, error) {
        return askTheUser(tool, args, d.Reason)
    },
    OnEvent: func(ev abhed.Event) { log.Println(ev.Type) },
})
if err != nil {
    return err
}
defer a.Close()

answer, err := a.Run(ctx, "fix the failing tests")

The surface

MethodPurpose
Newbuild an agent from options, a config directory, or both
Run, Continuesend a prompt; Continue keeps the conversation
Steerredirect a run already in progress, from another goroutine
Forkrebuild the conversation up to a sequence number
Eventseverything recorded; the stream is the session
Usagetokens, turns, cache hit rate, compactions
ExportHTMLa self-contained transcript
SetModelswap providers mid-conversation, keeping history
Providersthe provider types this build supports

What does not change when embedded

Policy still decides what runs. Every action is still recorded as an event, so an embedded session replays exactly like one from the CLI. An extension still may veto and never permit.

One difference is deliberate: an agent with no Approve function refuses anything needing approval rather than assuming yes. A service with nobody to ask should be stricter than a terminal with somebody watching, not looser — defaulting to permissive would make the SDK quietly weaker than the same policy on the command line.

Driving it from another language

abhed rpc speaks line-delimited JSON on stdin and stdout, for callers that are not Go. See 15-extensions.md.

What is not here yet

Subscription auth. Pi can sign in with a Claude Pro, ChatGPT Plus or GitHub Copilot subscription. Abhed takes an API key. Closing this needs each vendor's OAuth device flow and token refresh, one at a time — real work, and worth doing, but not a change to the harness.