adapter

package
v0.46.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package adapter defines interfaces for all external integrations. Engines depend on these interfaces, never on concrete implementations.

Index

Constants

This section is empty.

Variables

View Source
var ErrNotSupported = errors.New("not supported by this agent provider")

ErrNotSupported reports that a provider does not implement the requested plane. Callers test for it with errors.Is and degrade gracefully — a completion-only provider has no session plane, and a session-only harness that cannot prove tool containment has no completion plane. Never match on the message text.

View Source
var ErrRecipientUnknown = errors.New("comms: recipient handle not resolvable")

ErrRecipientUnknown is returned by NotifyUser when an adapter cannot resolve a handle to a user it can message directly. Callers fall back to a channel broadcast — this is never a fatal condition.

Functions

This section is empty.

Types

type AgentAdapter

type AgentAdapter interface {
	// Invoke spawns the agent as a subprocess. It blocks until the agent exits.
	Invoke(ctx context.Context, req InvokeRequest) (*InvokeResult, error)
	// Generate performs a single contained completion. Implementations must not
	// grant the model tools, repo access, or interactivity.
	Generate(ctx context.Context, req GenerateRequest) (*GenerateResult, error)
	// Capabilities describes what the agent harness supports.
	Capabilities() Capabilities
}

AgentAdapter manages coding agent integration across two planes of the same capability.

The session plane (Invoke) spawns the agent as an interactive or headless subprocess with MCP config, skills, and a system prompt: this is the build and interactive-authoring contract. The completion plane (Generate) is one-shot, contained generation for drafting and summarising — no tools, no repo access, no interactivity.

A provider need not implement both. Consumers negotiate via Capabilities before use, and an unimplemented plane returns ErrNotSupported.

type Capabilities added in v0.15.0

type Capabilities struct {
	// MCP reports whether the harness can be given an MCP server config.
	MCP bool
	// Headless reports whether the harness has a non-interactive mode.
	Headless bool
	// Skills reports whether the harness accepts skill paths.
	Skills bool
	// SystemPrompt reports whether the harness accepts a system prompt.
	SystemPrompt bool
	// Generate reports whether the completion plane is available. For a
	// session-capable harness this is true only when the adapter can prove
	// tool containment (hard tool-disable flags asserted by contract test);
	// a harness that cannot be contained does not advertise completions.
	Generate bool
	// StructuredOutput reports whether the provider enforces a JSON schema
	// natively. When false, FormatJSON degrades to schema-in-prompt and the
	// caller parses defensively.
	StructuredOutput bool
}

Capabilities describes the features an agent harness supports. Consumers read this once and gate their affordances on it: an unsupported action must be explained, never offered and then failed.

type CommsAdapter

type CommsAdapter interface {
	// Notify sends a structured message to the configured channel.
	Notify(ctx context.Context, msg Notification) error
	// NotifyUser sends a notification directly to a specific user by handle,
	// bypassing the channel broadcast. Adapters that cannot resolve a handle
	// to a user, or that have no per-user delivery mechanism at all, return
	// ErrRecipientUnknown so the caller can fall back to Notify. Like every
	// comms call it is best-effort and never fatal.
	NotifyUser(ctx context.Context, handle string, msg Notification) error
	// PostStandup posts a formatted standup to the standup channel.
	PostStandup(ctx context.Context, standup StandupReport) error
	// FetchMentions returns recent mentions of spec IDs in configured channels.
	FetchMentions(ctx context.Context, since time.Time) ([]Mention, error)
}

CommsAdapter sends notifications and retrieves mentions from a comms platform.

type ContextPart added in v0.44.0

type ContextPart struct {
	Label   string
	Content string
	Weight  int
}

ContextPart is a labelled block of context with a trimming weight. Higher weights survive budget trimming; see internal/llm for the assembly rules.

type DeployAdapter

type DeployAdapter interface {
	// Trigger initiates a deployment for the given repos to the target environment.
	Trigger(ctx context.Context, repos []string, env string) (*DeployRun, error)
	// Status polls the deployment run for current state.
	Status(ctx context.Context, run *DeployRun) (*DeployStatus, error)
}

DeployAdapter manages deployment integration.

type DeployRun

type DeployRun struct {
	ID     string
	Repo   string
	Env    string
	Status string
	URL    string
}

DeployRun represents a triggered deployment.

type DeployStatus

type DeployStatus struct {
	RunID   string
	Status  string // "pending", "running", "success", "failure"
	URL     string
	Message string
}

DeployStatus represents the current state of a deployment.

type DocsAdapter

type DocsAdapter interface {
	// FetchSections retrieves the current content of the spec from the docs provider,
	// keyed by section slug.
	FetchSections(ctx context.Context, specID string) (map[string]string, error)
	// PushFull publishes the complete spec to the docs provider.
	PushFull(ctx context.Context, specID string, content string) error
	// PageURL returns the URL of the spec's page in the docs provider.
	PageURL(ctx context.Context, specID string) (string, error)
}

DocsAdapter manages documentation tool integration.

type GenerateRequest added in v0.44.0

type GenerateRequest struct {
	// Task is the stable task id (e.g. "draft-section"), used for telemetry
	// and to scope per-task budgets.
	Task string
	// System is the task-specific system prompt.
	System string
	// Prompt is the assembled user prompt.
	Prompt string
	// Context carries labelled blocks the adapter appends verbatim. Assembly
	// and trimming happen before the adapter sees the request.
	Context []ContextPart
	// MaxTokens caps the response. Honoured by completion-API providers only;
	// headless harnesses expose no token cap and ignore it. 0 = provider
	// default.
	MaxTokens int
	// Format selects the output shape. FormatJSON is only honoured when
	// Capabilities.StructuredOutput is true; otherwise the caller is expected
	// to have embedded the schema in the prompt and to parse defensively.
	Format OutputFormat
	// Schema is the JSON schema for Format == FormatJSON. Ignored otherwise.
	Schema json.RawMessage
}

GenerateRequest is a single contained completion request. The caller (the task registry in internal/llm) owns all prompt assembly; the adapter only translates this into its provider's wire format or CLI invocation.

type GenerateResult added in v0.44.0

type GenerateResult struct {
	// Text is the generated content.
	Text string
	// Tokens reports usage when the provider supplies it; zero = unreported.
	Tokens TokenUsage
	// Model names what served the request, when known.
	Model string
	// Raw holds a bounded tail of provider output, populated only when
	// structured parsing yielded no text. Lets output-format drift degrade
	// into a debuggable empty result instead of an error.
	Raw string
}

GenerateResult carries a completion and what it cost. All fields except Text are best-effort: a provider that does not report usage leaves Tokens zero, and a provider that does not name its model leaves Model empty. Callers must treat empty fields as "unknown", never as an error.

type InvokeRequest added in v0.15.0

type InvokeRequest struct {
	SpecID        string   // active spec id (e.g. SPEC-042)
	WorkDir       string   // working directory the agent runs in
	ContextFile   string   // consolidated markdown fallback for non-MCP agents
	MCPConfigPath string   // engine-generated; runs `spec mcp-server --spec <id>`
	SystemPrompt  string   // assembled build instructions
	SkillPaths    []string // reproducibility skill paths (may be empty)
	Prompt        string   // kickoff prompt (may be empty)
	Headless      bool     // -p mode for `spec fix --auto` / CI
}

InvokeRequest carries everything an agent needs for a build session.

type InvokeResult added in v0.15.0

type InvokeResult struct {
	// ExitReason is why the session ended: "completed", "error",
	// "interrupted", or "" when it could not be determined.
	ExitReason string `json:"exitReason,omitempty"`
	// ErrorClass categorises a failure (e.g. "auto_retry_exhausted",
	// "compaction_failed", "nonzero_exit"). Empty on success.
	ErrorClass string `json:"errorClass,omitempty"`
	// ErrorMessage is the harness-reported failure detail, when present.
	ErrorMessage string `json:"errorMessage,omitempty"`
	// Tokens aggregates token usage across the session, when the harness
	// reports it.
	Tokens TokenUsage `json:"tokens,omitempty"`
	// Raw holds a bounded tail of the harness output, retained for debugging
	// when structured parsing yields nothing.
	Raw string `json:"raw,omitempty"`
}

InvokeResult reports what the agent did during the session. spec-cli reconciles real per-node progress from the durable node ledger after the agent exits; this result carries the session-level signal that the ledger cannot capture — why the run ended, how it failed, and what it cost — so that autonomous (`--auto`) runs are debuggable from the activity log.

All fields are best-effort. A headless harness whose output cannot be parsed yields a zero-value result with Raw populated; callers must treat empty fields as "unknown", never as an error.

type Mention

type Mention struct {
	SpecID    string
	Channel   string
	Author    string
	Preview   string
	Timestamp time.Time
}

Mention represents a comms mention of a spec.

type Notification

type Notification struct {
	SpecID  string
	Title   string
	Message string
	Channel string
	Mention string // e.g., "@alice"
}

Notification represents a structured message to send via comms.

type OutputFormat added in v0.44.0

type OutputFormat int

OutputFormat selects the shape of a Generate response.

const (
	// FormatMarkdown is prose or markdown output. The default.
	FormatMarkdown OutputFormat = iota
	// FormatJSON requests structured output against GenerateRequest.Schema.
	FormatJSON
)

type PMAdapter

type PMAdapter interface {
	// FindEpic returns the key of an existing PM object linked to the spec, or
	// "" when none exists. It is the idempotency guard for CreateEpic and
	// CreateTask alike: a spec that already has a PM object is linked, never
	// converted to another type.
	FindEpic(ctx context.Context, specID string) (pmKey string, err error)
	// CreateEpic creates a new epic/issue linked to a spec and returns its key.
	// Used for a standalone spec and for an initiative.
	CreateEpic(ctx context.Context, spec SpecMeta) (pmKey string, err error)
	// CreateTask creates a task under an existing epic, for a spec that is a
	// deliverable slice of an initiative. parentKey is the parent spec's PM
	// key. Implementations return ("", nil) when they cannot place the task,
	// so a PM shortfall never blocks the spec-side link.
	CreateTask(ctx context.Context, spec SpecMeta, parentKey string) (pmKey string, err error)
	// LinkEpic records a back-link from the PM issue to the spec so board
	// consumers can navigate PM -> spec. specURL may be empty.
	LinkEpic(ctx context.Context, pmKey, specID, specURL string) error
	// UpdateStatus syncs the spec's pipeline stage to the PM tool's board
	// status. A stage with no configured mapping is a clean no-op.
	UpdateStatus(ctx context.Context, pmKey string, status string) error
	// FetchUpdates returns status changes from the PM tool since last sync.
	FetchUpdates(ctx context.Context, pmKey string) (*PMUpdate, error)
	// SyncStories reconciles per-step children of a PM object, returning the
	// resulting story links. The adapter resolves the object's type from pmKey
	// and chooses the appropriate child issue type. A no-op when story sync is
	// disabled.
	SyncStories(ctx context.Context, pmKey string, stories []StorySpec) ([]StoryLink, error)
	// Validate checks credentials and configuration against the live PM tool.
	Validate(ctx context.Context) error
}

PMAdapter manages project management tool integration.

Implementations must be idempotent and degrade gracefully: an unconfigured or unreachable PM tool returns empty results and nil errors rather than blocking spec authoring (see docs/JIRA_HARDENING_PLAN.md).

The interface deliberately does not name issue types beyond the two verbs spec needs. A PM tool's issue-type taxonomy is provider knowledge that lives in its adapter package; spec stores only a key (`pm_key`) and lets the adapter resolve the type from it.

type PMUpdate

type PMUpdate struct {
	Status    string
	Assignee  string
	UpdatedAt time.Time
}

PMUpdate represents status changes from a PM tool.

type PRDetail

type PRDetail struct {
	PullRequest
	ReviewComments    int
	UnresolvedThreads int
}

PRDetail represents detailed PR information.

type PullRequest

type PullRequest struct {
	Number    int
	Title     string
	Repo      string
	Branch    string
	Author    string
	URL       string
	Status    string // "open", "merged", "closed"
	Draft     bool   // PR is a draft: opened for visibility, not yet review-ready
	Approved  bool
	CIStatus  string // "passing", "failing", "pending"
	CreatedAt time.Time
}

PullRequest represents a PR from a repo provider.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry resolves configuration to concrete adapter implementations.

func NewRegistry

func NewRegistry(cfg *config.TeamConfig) *Registry

NewRegistry creates a new adapter registry from team configuration. Concrete adapters are injected via With* methods. Unconfigured adapters are set to their noop implementations by the caller.

func (*Registry) Agent

func (r *Registry) Agent() AgentAdapter

Agent returns the agent adapter.

func (*Registry) Comms

func (r *Registry) Comms() CommsAdapter

Comms returns the comms adapter.

func (*Registry) Config

func (r *Registry) Config() *config.TeamConfig

Config returns the team configuration.

func (*Registry) Deploy

func (r *Registry) Deploy() DeployAdapter

Deploy returns the deploy adapter.

func (*Registry) Docs

func (r *Registry) Docs() DocsAdapter

Docs returns the docs adapter.

func (*Registry) PM

func (r *Registry) PM() PMAdapter

PM returns the PM adapter.

func (*Registry) Repo

func (r *Registry) Repo() RepoAdapter

Repo returns the repo adapter.

func (*Registry) WithAgent

func (r *Registry) WithAgent(a AgentAdapter) *Registry

WithAgent sets the agent adapter.

func (*Registry) WithComms

func (r *Registry) WithComms(a CommsAdapter) *Registry

WithComms sets the comms adapter.

func (*Registry) WithDeploy

func (r *Registry) WithDeploy(a DeployAdapter) *Registry

WithDeploy sets the deploy adapter.

func (*Registry) WithDocs

func (r *Registry) WithDocs(a DocsAdapter) *Registry

WithDocs sets the docs adapter.

func (*Registry) WithPM

func (r *Registry) WithPM(a PMAdapter) *Registry

WithPM sets the PM adapter.

func (*Registry) WithRepo

func (r *Registry) WithRepo(a RepoAdapter) *Registry

WithRepo sets the repo adapter.

type RepoAdapter

type RepoAdapter interface {
	// ListPRs returns open PRs matching a spec's branch pattern across its repos.
	ListPRs(ctx context.Context, repos []string, specID string) ([]PullRequest, error)
	// PRStatus returns the review/CI status of a specific PR.
	PRStatus(ctx context.Context, repo string, prNumber int) (*PRDetail, error)
	// SetPRDescription updates a PR's description.
	SetPRDescription(ctx context.Context, repo string, prNumber int, body string) error
	// RequestedReviews returns PRs where the current user is a requested reviewer.
	RequestedReviews(ctx context.Context, user string) ([]PullRequest, error)
	// InvolvedPRs returns open PRs that involve the user in any capacity —
	// authored, assigned, review-requested, or mentioned. Unlike
	// RequestedReviews, this includes the user's own PRs.
	InvolvedPRs(ctx context.Context, user string) ([]PullRequest, error)
	// OpenDraftPR opens a DRAFT pull request from head into base, returning its
	// number and URL. Draft-only by design: merge stays a human action, so no
	// merge call is exposed on this interface.
	OpenDraftPR(ctx context.Context, repo, head, base, title, body string) (number int, url string, err error)
	// SetPRBase retargets an open PR's base branch, used to re-chain a stack as
	// parent PRs merge.
	SetPRBase(ctx context.Context, repo string, prNumber int, base string) error
}

RepoAdapter manages code repository integration.

type SpecMeta

type SpecMeta struct {
	ID      string
	Title   string
	Status  string
	EpicKey string
	Repos   []string

	// Problem is a short excerpt of the problem statement, used to give the
	// PM epic meaningful context instead of just an id.
	Problem string
	// Labels are applied to the created issue (in addition to config labels).
	Labels []string
	// Cycle is the team cycle/iteration label.
	Cycle string
	// URL is a back-link to the canonical spec document.
	URL string
}

SpecMeta is a lightweight spec summary for adapter use.

type StandupReport

type StandupReport struct {
	UserName  string
	Date      string
	Yesterday []string
	Today     []string
	Blockers  []string
}

StandupReport represents a formatted standup.

type StoryLink struct {
	StepID   string
	StoryKey string
	Status   string
}

StoryLink is the result of reconciling a StorySpec: the PM story key and the status it was left in.

type StorySpec added in v0.22.1

type StorySpec struct {
	// StepID is a stable identifier for the step, used as the idempotency key.
	StepID      string
	Repo        string
	Description string
	// Status is the spec step status: pending | in-progress | complete | blocked.
	Status string
}

StorySpec describes a build step to reconcile into a PM story under an epic.

type TokenUsage added in v0.23.0

type TokenUsage struct {
	Input  int `json:"input,omitempty"`
	Output int `json:"output,omitempty"`
	Total  int `json:"total,omitempty"`
}

TokenUsage aggregates the token counts a headless harness reports over a session. Zero values mean the harness did not report that figure.

Directories

Path Synopsis
Package anthropic implements the agent completion plane using the Anthropic Messages API.
Package anthropic implements the agent completion plane using the Anthropic Messages API.
Package claude implements AgentAdapter for Claude Code.
Package claude implements AgentAdapter for Claude Code.
Package confluence implements DocsAdapter using the Confluence REST API.
Package confluence implements DocsAdapter using the Confluence REST API.
Package github implements RepoAdapter and DeployAdapter using the GitHub API.
Package github implements RepoAdapter and DeployAdapter using the GitHub API.
Package harness holds the shared machinery for running a coding harness as a contained one-shot completion.
Package harness holds the shared machinery for running a coding harness as a contained one-shot completion.
Package jira implements PMAdapter using the Jira REST API v3.
Package jira implements PMAdapter using the Jira REST API v3.
Package noop provides no-op adapter implementations for unconfigured integrations.
Package noop provides no-op adapter implementations for unconfigured integrations.
Package openaicompat implements the agent completion plane against any OpenAI-compatible /v1/chat/completions endpoint.
Package openaicompat implements the agent completion plane against any OpenAI-compatible /v1/chat/completions endpoint.
Package pi implements AgentAdapter for the pi.dev coding agent.
Package pi implements AgentAdapter for the pi.dev coding agent.
Package resolve creates concrete adapter implementations from team config.
Package resolve creates concrete adapter implementations from team config.
Package slack implements CommsAdapter using the Slack API.
Package slack implements CommsAdapter using the Slack API.
Package teams implements CommsAdapter using Microsoft Teams webhooks.
Package teams implements CommsAdapter using Microsoft Teams webhooks.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL