Documentation
¶
Overview ¶
Package adapter defines interfaces for all external integrations. Engines depend on these interfaces, never on concrete implementations.
Index ¶
- Variables
- type AgentAdapter
- type Capabilities
- type CommsAdapter
- type ContextPart
- type DeployAdapter
- type DeployRun
- type DeployStatus
- type DocsAdapter
- type GenerateRequest
- type GenerateResult
- type InvokeRequest
- type InvokeResult
- type Mention
- type Notification
- type OutputFormat
- type PMAdapter
- type PMUpdate
- type PRDetail
- type PullRequest
- type Registry
- func (r *Registry) Agent() AgentAdapter
- func (r *Registry) Comms() CommsAdapter
- func (r *Registry) Config() *config.TeamConfig
- func (r *Registry) Deploy() DeployAdapter
- func (r *Registry) Docs() DocsAdapter
- func (r *Registry) PM() PMAdapter
- func (r *Registry) Repo() RepoAdapter
- func (r *Registry) WithAgent(a AgentAdapter) *Registry
- func (r *Registry) WithComms(a CommsAdapter) *Registry
- func (r *Registry) WithDeploy(a DeployAdapter) *Registry
- func (r *Registry) WithDocs(a DocsAdapter) *Registry
- func (r *Registry) WithPM(a PMAdapter) *Registry
- func (r *Registry) WithRepo(a RepoAdapter) *Registry
- type RepoAdapter
- type SpecMeta
- type StandupReport
- type StoryLink
- type StorySpec
- type TokenUsage
Constants ¶
This section is empty.
Variables ¶
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.
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
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 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 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) 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) 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) 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 ¶ added in v0.22.1
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.
Source Files
¶
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. |