Documentation
¶
Overview ¶
Package client is the public Go SDK for the Wardyn control plane. It uses internal/types as the shared JSON source of truth and adds exactly one non-stdlib dependency (github.com/google/uuid, for typed ids) so it can be embedded in external tooling without friction. The in-repo `wardyn` CLI uses THIS client directly (there is no second transport); it maps APIError to process exit codes and prints APIError.Error(), which unwraps the server's {"error":...} envelope into a human-readable message.
Coverage ¶
The SDK covers these wardynd public route families (the ones external tooling automates); it is a curated subset, NOT a 1:1 mirror of every route:
- runs: CreateRun, Preflight, GetRun, ListRuns, ListGrants, KillRun, SynthesizeProfile, GetRecording
- approvals: ListApprovals, Approve, Deny
- policies: CreatePolicy, GetPolicy, ListPolicies, UpdatePolicy, DeletePolicy
- workspaces: CreateWorkspace, GetWorkspace, ListWorkspaces, UpdateWorkspace, DeleteWorkspace, ScanWorkspace, RecordWorkspaceTask
- sources: ListSources, CreateSource, GetSource, ScanSource, DeleteSource
- audit: AuditEvents, AuditEventsPage, RecentAuditEvents
- secrets: ListSecrets, SetSecret, DeleteSecret
- site-config: GetSiteConfig, PutSiteConfig
- setup: SetupStatus, ConnectManagedSubscription, DisconnectManagedSubscription
- identity: Me
- health: Healthz
NOT covered (drive these with the CLI or raw HTTP): attach WebSocket / attach-ticket, harness-login device flow, and the agent-facing /internal/* mint & decision endpoints. (The AI Run Composer's /runs/compose* used to be listed here; those routes were removed in 0.5, not left unwrapped.) TestClientCoversRouteFamilies pins that every family listed above has a method.
Pagination ¶
The list endpoints and the audit trail accept an optional ListOpts (variadic, so existing zero-arg calls are unchanged) that sends ?limit=&offset=. A page may be truncated (the server sets X-Wardyn-Truncated); re-request with Offset advanced by len(page) to page forward. AuditEventsPage returns that signal directly as a bool instead of leaving a caller to infer completeness from len(page) == the limit it happened to pass — a guess that silently breaks the moment a caller omits Limit and gets the server's own default page size.
Usage:
c := client.New("https://wardyn.example.com", "admin-token")
run, err := c.CreateRun(ctx, client.CreateRunRequest{
Agent: "claude-code",
Repo: "org/repo",
Task: "fix issue #42",
})
Index ¶
- Constants
- type APIError
- type ActorType
- type AgentRun
- type ApprovalKind
- type ApprovalRequest
- type ApprovalScope
- type ApprovalState
- type ArtifactOverridedeprecated
- type AuditEvent
- type AuditFilter
- type BaseImageEntry
- type Client
- func (c *Client) Approve(ctx context.Context, id uuid.UUID, reason string, opts ...DecisionOpts) (types.ApprovalRequest, error)
- func (c *Client) AuditEvents(ctx context.Context, runID uuid.UUID, opts ...ListOpts) ([]types.AuditEvent, error)
- func (c *Client) AuditEventsPage(ctx context.Context, runID uuid.UUID, filter AuditFilter, opts ...ListOpts) (events []types.AuditEvent, truncated bool, err error)
- func (c *Client) ConnectManagedSubscription(ctx context.Context, provider, token string) error
- func (c *Client) CreatePolicy(ctx context.Context, req PolicyRequest) (types.RunPolicy, error)
- func (c *Client) CreateRun(ctx context.Context, req CreateRunRequest) (CreateRunResult, error)
- func (c *Client) CreateSource(ctx context.Context, req SourceRequest) (types.Source, error)
- func (c *Client) CreateWorkspace(ctx context.Context, req WorkspaceRequest) (types.Workspace, error)
- func (c *Client) DeletePolicy(ctx context.Context, id uuid.UUID) error
- func (c *Client) DeleteSecret(ctx context.Context, name string) error
- func (c *Client) DeleteSource(ctx context.Context, id uuid.UUID, force bool) (detachedFrom []string, err error)
- func (c *Client) DeleteWorkspace(ctx context.Context, id uuid.UUID) error
- func (c *Client) Deny(ctx context.Context, id uuid.UUID, reason string, opts ...DecisionOpts) (types.ApprovalRequest, error)
- func (c *Client) DisconnectManagedSubscription(ctx context.Context, provider string) error
- func (c *Client) GetPolicy(ctx context.Context, id uuid.UUID) (types.RunPolicy, error)
- func (c *Client) GetRecording(ctx context.Context, runID uuid.UUID, session ...string) (io.ReadCloser, error)
- func (c *Client) GetRun(ctx context.Context, id uuid.UUID) (types.AgentRun, error)
- func (c *Client) GetSiteConfig(ctx context.Context) (types.SiteConfig, error)
- func (c *Client) GetSource(ctx context.Context, id uuid.UUID) (types.Source, error)
- func (c *Client) GetWorkspace(ctx context.Context, id uuid.UUID) (types.Workspace, error)
- func (c *Client) Healthz(ctx context.Context) (json.RawMessage, error)
- func (c *Client) KillRun(ctx context.Context, id uuid.UUID) (KillRunResponse, error)
- func (c *Client) ListApprovals(ctx context.Context, state types.ApprovalState, opts ...ListOpts) ([]types.ApprovalRequest, error)
- func (c *Client) ListGrants(ctx context.Context, runID uuid.UUID) ([]types.CredentialGrant, error)
- func (c *Client) ListPolicies(ctx context.Context, opts ...ListOpts) ([]types.RunPolicy, error)
- func (c *Client) ListRuns(ctx context.Context, opts ...ListOpts) ([]types.AgentRun, error)
- func (c *Client) ListSecrets(ctx context.Context) ([]string, error)
- func (c *Client) ListSources(ctx context.Context) ([]types.Source, error)
- func (c *Client) ListWorkspaces(ctx context.Context, opts ...ListOpts) ([]types.Workspace, error)
- func (c *Client) Me(ctx context.Context) (json.RawMessage, error)
- func (c *Client) Preflight(ctx context.Context, req CreateRunRequest) (PreflightResult, error)
- func (c *Client) PutSiteConfig(ctx context.Context, cfg types.SiteConfig) (out types.SiteConfig, danglingSecretRefs []string, err error)
- func (c *Client) RecentAuditEvents(ctx context.Context, opts ...ListOpts) ([]types.AuditEvent, error)
- func (c *Client) RecordWorkspaceTask(ctx context.Context, wsID uuid.UUID, taskKey string) (RecordTaskResult, error)
- func (c *Client) ScanSource(ctx context.Context, id uuid.UUID) (json.RawMessage, error)
- func (c *Client) ScanWorkspace(ctx context.Context, id uuid.UUID) (json.RawMessage, error)
- func (c *Client) SetSecret(ctx context.Context, name, value string) error
- func (c *Client) SetupStatus(ctx context.Context) (json.RawMessage, error)
- func (c *Client) SynthesizeProfile(ctx context.Context, runID uuid.UUID) (ProfileResult, error)
- func (c *Client) UpdatePolicy(ctx context.Context, id uuid.UUID, req PolicyRequest) (types.RunPolicy, error)
- func (c *Client) UpdateWorkspace(ctx context.Context, id uuid.UUID, req WorkspaceRequest) (types.Workspace, error)
- type ConfinementClass
- type CreateRunRequest
- type CreateRunResult
- type CredentialGrant
- type DecisionOpts
- type EgressRedirect
- type GrantKind
- type GrantSpec
- type KillRunResponse
- type ListOpts
- type PolicyRequest
- type PreflightItem
- type PreflightResult
- type ProfileResult
- type RecordTaskResult
- type RunPolicy
- type RunPolicySpec
- type RunState
- type SiteConfig
- type Source
- type SourceKind
- type SourceRequest
- type Workspace
- type WorkspaceAttachment
- type WorkspaceBaseImage
- type WorkspaceBedrockRef
- type WorkspaceKind
- type WorkspaceLLMCred
- type WorkspaceMount
- type WorkspaceRequest
- type WorkspaceRequirement
- type WorkspaceSelection
- type WorkspaceSource
- type WorkspaceSourceType
- type WorkspaceStatus
Constants ¶
const ( SourceLocalDir = types.SourceLocalDir SourceRepo = types.SourceRepo )
SourceKind values (the tier-1 library's two onboardable kinds).
const ( ApprovalPending = types.ApprovalPending ApprovalApproved = types.ApprovalApproved ApprovalDenied = types.ApprovalDenied ApprovalExpired = types.ApprovalExpired )
ApprovalState values. ListApprovals accepts one of these (or "" for all states).
const ( ScopeOnce = types.ScopeOnce ScopeRun = types.ScopeRun ScopeUntil = types.ScopeUntil ScopeAlways = types.ScopeAlways )
ApprovalScope values, for DecisionOpts.Scope on Approve/Deny. Omitting Scope (or passing "") is ScopeRun — today's default, unchanged.
const ( RunPending = types.RunPending RunStarting = types.RunStarting RunRunning = types.RunRunning RunWaiting = types.RunWaiting RunStopped = types.RunStopped RunArchived = types.RunArchived RunFailed = types.RunFailed RunKilled = types.RunKilled RunCompleted = types.RunCompleted )
RunState values.
ConfinementClass values.
const ( GrantGitHubToken = types.GrantGitHubToken GrantGitPAT = types.GrantGitPAT GrantCloudSTS = types.GrantCloudSTS GrantAPIKey = types.GrantAPIKey GrantSSHKey = types.GrantSSHKey )
GrantKind values.
const ( ApprovalCredential = types.ApprovalCredential ApprovalEgressDomain = types.ApprovalEgressDomain ApprovalToolCall = types.ApprovalToolCall )
ApprovalKind values.
const ( ActorHuman = types.ActorHuman ActorAgent = types.ActorAgent ActorSystem = types.ActorSystem )
ActorType values.
const ( WorkspaceKindLocalDir = types.WorkspaceKindLocalDir WorkspaceKindRepo = types.WorkspaceKindRepo WorkspaceKindContainer = types.WorkspaceKindContainer )
WorkspaceKind values (WorkspaceRequest.Kind). Deprecated: the legacy single-source shape; a new caller should build WorkspaceSource entries with a WorkspaceSourceType value instead.
const ( WorkspaceSourceTypeLocalDir = types.WorkspaceSourceTypeLocalDir WorkspaceSourceTypeRepo = types.WorkspaceSourceTypeRepo WorkspaceSourceTypeEphemeral = types.WorkspaceSourceTypeEphemeral )
WorkspaceSourceType values (WorkspaceSource.Type).
const ( WorkspacePendingScan = types.WorkspacePendingScan WorkspaceScanning = types.WorkspaceScanning WorkspaceScanned = types.WorkspaceScanned WorkspaceError = types.WorkspaceError )
WorkspaceStatus values (Workspace.Status, Source.Status).
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type APIError ¶
type APIError struct {
// Status is the HTTP status code, e.g. 404.
Status int
// Body is the raw server response body (capped at 2048 bytes).
Body string
}
APIError is returned when the server responds with a non-2xx status code. Status is the HTTP status code; Body is the raw response body (trimmed to 2 KiB) for diagnostic display. Callers may use errors.As to extract it.
type AgentRun ¶
AgentRun is one governed execution of a coding agent. Returned by CreateRun, GetRun, and ListRuns.
type ApprovalKind ¶
type ApprovalKind = types.ApprovalKind
ApprovalKind enumerates what a human is being asked to approve (ApprovalRequest.Kind).
type ApprovalRequest ¶
type ApprovalRequest = types.ApprovalRequest
ApprovalRequest is a human-in-the-loop approval gate. Returned by ListApprovals, Approve, and Deny.
type ApprovalScope ¶ added in v0.5.0
type ApprovalScope = types.ApprovalScope
ApprovalScope is how far an Approve/Deny decision reaches: once, run (the default), until, or always. Set via DecisionOpts on Approve/Deny; read back on ApprovalRequest.DecisionScope. Meaningful only for an egress_domain approval — a credential mints once by construction and a tool_call is bounded by the clamp.
type ApprovalState ¶
type ApprovalState = types.ApprovalState
ApprovalState is the approval lifecycle state; ListApprovals filters on it (ApprovalRequest.State).
type ArtifactOverride
deprecated
added in
v0.4.4
type ArtifactOverride = types.ArtifactOverride
ArtifactOverride is one ecosystem's artifact-registry redirect, carried in the deprecated SiteConfig.ArtifactOverrides.
Deprecated: superseded by EgressRedirect. Kept aliased so a caller that still builds the legacy shape (PutSiteConfig folds it server-side for one release) can name the element type; GetSiteConfig itself now returns this field empty.
type AuditEvent ¶
type AuditEvent = types.AuditEvent
AuditEvent is one append-only audit record. Returned by AuditEvents.
type AuditFilter ¶ added in v0.5.0
type AuditFilter struct {
Since string // RFC3339, e.g. time.Now().UTC().Format(time.RFC3339)
Until string // RFC3339
ActionPrefix string
ActorType string // "human" | "agent" | "system"
Outcome string // "success" | "denied" | "failure"
}
AuditFilter narrows an audit query by the server's optional predicates — ?since=&until=&action_prefix=&actor_type=&outcome= (see docs/sdk.md's Raw HTTP section). The zero value applies no filter. Since/Until are RFC3339 strings; a malformed one is rejected by the server as a 400, same as the raw HTTP API — the client does not duplicate that validation.
type BaseImageEntry ¶ added in v0.5.0
type BaseImageEntry = types.BaseImageEntry
BaseImageEntry is one tier-2 base-image catalog row: a shared, reusable image an operator saved (kind registry|custom|byo).
type Client ¶
type Client struct {
// BaseURL is the wardynd root, e.g. "https://wardyn.example.com".
// A trailing slash is stripped automatically.
BaseURL string
// Token is the admin bearer token configured in wardynd (AdminToken).
Token string
// HTTPClient, when non-nil, is used instead of http.DefaultClient.
HTTPClient *http.Client
// Principal, when non-empty, is sent as the X-Wardyn-Principal header — a
// DEV-ONLY override for simulating different principals against a local
// wardynd. The server honors it ONLY in local (no-auth) mode. Under
// admin-token auth it is ignored and the action is attributed to
// actor_type=system / principal "admin-token" (the token is an opaque shared
// bearer, not a JWT — there is no subject to extract); under OIDC the
// verified subject wins. Use OIDC for real per-human attribution.
Principal string
}
Client is the Wardyn SDK client. Construct it with New or by filling the fields directly. BaseURL and Token are required; HTTPClient defaults to http.DefaultClient when nil.
All methods accept a context; the context controls cancellation and deadline for the underlying HTTP call.
func (*Client) Approve ¶
func (c *Client) Approve(ctx context.Context, id uuid.UUID, reason string, opts ...DecisionOpts) (types.ApprovalRequest, error)
Approve transitions an approval request to APPROVED. reason is optional; pass an empty string to omit it. opts is optional (pass at most one); omitting it keeps today's default — a run-scoped approval. See DecisionOpts for once/until/always. Returns 409/APIError when the approval has already been decided. Returns 404/APIError when the approval does not exist.
func (*Client) AuditEvents ¶
func (c *Client) AuditEvents(ctx context.Context, runID uuid.UUID, opts ...ListOpts) ([]types.AuditEvent, error)
AuditEvents returns the append-only audit trail for the specified run in chronological (seq ASC) order, unfiltered. run_id is required by the server; a zero UUID is rejected with 400. Pass a ListOpts to page a long trail: a truncated page (server sets X-Wardyn-Truncated) is walked forward with Offset += len(page), which reaches the terminal run.complete event under ASC order — prefer AuditEventsPage, which returns that signal directly instead of requiring the caller to infer it.
func (*Client) AuditEventsPage ¶ added in v0.5.0
func (c *Client) AuditEventsPage(ctx context.Context, runID uuid.UUID, filter AuditFilter, opts ...ListOpts) (events []types.AuditEvent, truncated bool, err error)
AuditEventsPage is AuditEvents plus the server's X-Wardyn-Truncated signal and the optional filter predicates (AuditFilter): truncated=true means this page did NOT reach the run's newest event (including run.complete, since the per-run trail is chronological/ASC) and the caller must page forward — Offset += len(events) — to see the rest. This is the fix for the audit-gap where a >1000-event run's newest events could silently drop with no way for a caller to even detect it: AuditEvents alone (below) cannot tell "this is everything" from "this is page 1 of more".
func (*Client) ConnectManagedSubscription ¶ added in v0.4.0
ConnectManagedSubscription stores a captured provider setup-token so the proxy injects it into every eligible run (never resident in the sandbox). The value is write-only. PUT /api/v1/setup/harness-credential/{provider}.
func (*Client) CreatePolicy ¶
CreatePolicy validates and persists a new policy. Returns the created RunPolicy (status 201) on success; 400 on an invalid name or spec.
func (*Client) CreateRun ¶
func (c *Client) CreateRun(ctx context.Context, req CreateRunRequest) (CreateRunResult, error)
CreateRun submits a new agent run to the control plane. Returns the created run (state PENDING or RUNNING) plus any advisory warnings. Status 201 on success; 400 on validation failure; 422 on policy/confinement mismatch; 503 when the runner is unavailable.
func (*Client) CreateSource ¶ added in v0.5.0
CreateSource upserts a library source by canonical identity (201 new, 200 existing row). POST /api/v1/sources.
func (*Client) CreateWorkspace ¶ added in v0.3.1
func (c *Client) CreateWorkspace(ctx context.Context, req WorkspaceRequest) (types.Workspace, error)
CreateWorkspace onboards a new workspace (status pending_scan). Returns the created row (201); 400 on an invalid body/source.
func (*Client) DeletePolicy ¶
DeletePolicy removes a policy by id. Returns nil on success (204); 404/APIError when the policy does not exist.
func (*Client) DeleteSecret ¶
DeleteSecret removes a named secret. DELETE /api/v1/secrets/{name}. Returns 403 for a reserved platform-internal name.
func (*Client) DeleteSource ¶ added in v0.5.0
func (c *Client) DeleteSource(ctx context.Context, id uuid.UUID, force bool) (detachedFrom []string, err error)
DeleteSource removes a library source. In use → 409 APIError naming the attaching workspaces; force detaches them first — those workspaces just stop mounting this source, and their next runs succeed without it (there is no loud failure at run time: the mount gate has nothing to check for a source that used to be there). detachedFrom names whichever workspaces the delete actually detached (empty when the source wasn't attached to any), the only visibility into what changed. DELETE /api/v1/sources/{id}[?force=1].
func (*Client) DeleteWorkspace ¶ added in v0.3.1
DeleteWorkspace removes a workspace by id. Returns nil (204); 404 when unknown.
func (*Client) Deny ¶
func (c *Client) Deny(ctx context.Context, id uuid.UUID, reason string, opts ...DecisionOpts) (types.ApprovalRequest, error)
Deny transitions an approval request to DENIED (fail closed). reason is optional; pass an empty string to omit it. opts is optional (pass at most one); omitting it keeps today's default — a run-scoped denial. See DecisionOpts for once/until/always. Returns 409/APIError when the approval has already been decided. Returns 404/APIError when the approval does not exist.
func (*Client) DisconnectManagedSubscription ¶ added in v0.4.0
DisconnectManagedSubscription removes a provider's stored managed subscription token. DELETE /api/v1/setup/harness-credential/{provider}.
func (*Client) GetPolicy ¶
GetPolicy fetches a single RunPolicy by its UUID. Returns 404/APIError when the policy does not exist.
func (*Client) GetRecording ¶ added in v0.4.4
func (c *Client) GetRecording(ctx context.Context, runID uuid.UUID, session ...string) (io.ReadCloser, error)
GetRecording streams a run's terminal recording as raw asciicast bytes (the .cast a player consumes). The caller MUST Close the returned reader. GET /api/v1/runs/{id}/recording/{key} — the id really does appear twice: the route is mounted per-run and its handler takes the recording's own CAST KEY, which defaults to the bare run id (a batch run's single recording) when session is omitted — existing zero-arg callers are unaffected. An INTERACTIVE run can carry multiple recordings, one per attach session, each keyed "<runID>~<session>" (recording.CastKey — see internal/recording's own doc comment); pass that session id as the optional session argument to fetch one of those instead of the run's own bare-id cast. At most one value is meaningful; variadic only to keep it optional without a second method name. Returns 404/APIError when the run/session has no recording.
func (*Client) GetRun ¶
GetRun fetches a single AgentRun by its UUID. Returns 404/APIError when the run does not exist.
func (*Client) GetSiteConfig ¶ added in v0.3.1
GetSiteConfig returns the operator-wide site config. GET /api/v1/site-config.
func (*Client) GetSource ¶ added in v0.5.0
GetSource fetches one library source. GET /api/v1/sources/{id}.
func (*Client) GetWorkspace ¶ added in v0.3.1
GetWorkspace fetches a single workspace by id. Returns 404/APIError when unknown.
func (*Client) Healthz ¶ added in v0.3.1
Healthz returns the control-plane health payload as raw JSON. GET /healthz (note: NOT under /api/v1, and unauthenticated).
func (*Client) KillRun ¶
KillRun initiates the kill sequence for a run: durable state transition (compare-and-swap to KILLED) first, then sandbox teardown, identity revocation, and credential revocation. Returns 202/Accepted with the final state on success. Returns 404/APIError when the run does not exist.
func (*Client) ListApprovals ¶
func (c *Client) ListApprovals(ctx context.Context, state types.ApprovalState, opts ...ListOpts) ([]types.ApprovalRequest, error)
ListApprovals returns approval requests filtered by state. Pass an empty string to return all states. Valid states: "PENDING", "APPROVED", "DENIED", "EXPIRED" (types.ApprovalState).
func (*Client) ListGrants ¶
ListGrants returns the credential-grant eligibility records for a run. These are eligibility records (what the run MAY request), not issued credentials — some may never be minted. Returns 404/APIError when the run does not exist.
func (*Client) ListPolicies ¶
ListPolicies returns run policies in reverse creation order. Pass a ListOpts to page.
func (*Client) ListSecrets ¶
ListSecrets returns the managed secret NAMES (never values). Reserved platform-internal keys are excluded server-side. GET /api/v1/secrets, which responds {"names":[...]}.
func (*Client) ListSources ¶ added in v0.5.0
ListSources returns the whole library. GET /api/v1/sources.
func (*Client) ListWorkspaces ¶ added in v0.3.1
ListWorkspaces returns onboarded workspaces in reverse creation order. Pass a ListOpts to page.
func (*Client) Me ¶ added in v0.3.1
Me returns the caller's resolved identity/attribution as raw JSON. GET /api/v1/me.
func (*Client) Preflight ¶ added in v0.4.4
func (c *Client) Preflight(ctx context.Context, req CreateRunRequest) (PreflightResult, error)
Preflight DRY-RUNs a create-run request: the server resolves the policy through the same chokepoint launch uses (so an XOR violation, an unknown secret, or a non-onboarded workspace surface as the REAL launch error) and returns the setup checklist plus the enforced confinement class. It mints nothing, persists nothing, dispatches nothing. Pass the exact CreateRunRequest you would launch with. POST /api/v1/runs/preflight.
func (*Client) PutSiteConfig ¶ added in v0.3.1
func (c *Client) PutSiteConfig(ctx context.Context, cfg types.SiteConfig) (out types.SiteConfig, danglingSecretRefs []string, err error)
PutSiteConfig replaces the operator-wide site config and returns the persisted value plus danglingSecretRefs — the names of any secret the document now references that the secret store doesn't currently hold (e.g. a `site-config apply` recovery run before the referenced secrets were restored). Advisory only, never an error: the ref is still saved as given. PUT /api/v1/site-config.
Integrations is stripped from cfg before the request: the server rejects a non-empty one outright (integrations are managed through their own endpoints, never PUT /site-config), so the documented disaster-recovery round-trip — `wardyn site-config get > f` before a reset, `wardyn site-config apply f` after — 400ed outright the moment any integration was ever stored (PLATFORM-API-5). Stripped here, once, so no caller has to remember to (mirrors ui/src/app/lib/api/health.ts's identical fix on the TS side).
func (*Client) RecentAuditEvents ¶ added in v0.3.1
func (c *Client) RecentAuditEvents(ctx context.Context, opts ...ListOpts) ([]types.AuditEvent, error)
RecentAuditEvents returns the newest-first global audit feed (all runs) — the SIEM-style tail the Audit view renders. Pass a ListOpts to page.
func (*Client) RecordWorkspaceTask ¶ added in v0.3.1
func (c *Client) RecordWorkspaceTask(ctx context.Context, wsID uuid.UUID, taskKey string) (RecordTaskResult, error)
RecordWorkspaceTask launches a named open (allow-all egress) recording session for a workspace via the import pipeline — the operator attaches, does the real activity, and stops the run to capture what it actually used. POST /api/v1/workspaces/{id}/record with body {"task_key": name}. Returns 202 with the launched run; 503 when no runner is wired; 409 while another import step is live.
func (*Client) ScanSource ¶ added in v0.5.0
ScanSource scans one source — a dir inline (200 with the profile), a repo as a governed run (202 with scan_run_id). The reply shape varies, so it is returned raw. POST /api/v1/sources/{id}/scan.
func (*Client) ScanWorkspace ¶ added in v0.3.1
ScanWorkspace triggers the workspace scan (populates the least-privilege profile). The reply shape varies (a completed profile vs an accepted async run), so it is returned as raw JSON. POST /api/v1/workspaces/{id}/scan.
func (*Client) SetSecret ¶
SetSecret stores (or overwrites) a named secret. The value is write-only — no API path ever returns it. PUT /api/v1/secrets/{name} with body {"value":...}. Returns 400 on an invalid name, 403 for a reserved platform-internal name.
func (*Client) SetupStatus ¶ added in v0.3.1
SetupStatus returns the first-run setup checklist as raw JSON (the response is a server-internal struct not exported through internal/types). GET /api/v1/setup/status.
func (*Client) SynthesizeProfile ¶ added in v0.3.1
SynthesizeProfile runs Recording Mode synthesis for a run: from its already- captured audit / egress / ground-truth events the server proposes a tightened, reusable RunPolicy ("sandbox profile"). ADVISORY and READ-ONLY — it mints nothing and persists no policy (save the proposal via CreatePolicy). POST /api/v1/runs/{id}/profile. Returns 404 when the run does not exist.
type ConfinementClass ¶
type ConfinementClass = types.ConfinementClass
ConfinementClass declares how strongly a sandbox confines an agent (AgentRun.ConfinementClass, RunPolicySpec.MinConfinementClass).
type CreateRunRequest ¶
type CreateRunRequest struct {
Agent string `json:"agent"`
Repo string `json:"repo"`
// Task is the agent's prompt for a non-interactive run. For an interactive
// run it is instead the OPTIONAL boot seed: interpreted per
// InteractiveStart (an initial prompt for "agent", a startup command for
// "shell") and fired once, at sandbox boot, in the same persistent session
// the human later attaches to — never re-run on attach. Empty is today's
// pure-idle behavior, unchanged.
Task string `json:"task,omitempty"`
// Title is a short human NAME for the run. Runs that share a title are
// grouped in the console's run list. OPTIONAL on the wire even though the
// console requires it: the site-config probe, harness login and workspace
// record/verify all create runs with no human to name them, and the console
// falls back to Task for display. Trimmed and stored on the run row.
Title string `json:"title,omitempty"`
// Description is optional free-text context — why this run exists. Never
// interpreted, only stored and displayed.
Description string `json:"description,omitempty"`
PolicyID *uuid.UUID `json:"policy_id,omitempty"`
// ConfinementClass, when set, requests a specific confinement class
// ("CC1"/"CC2"/"CC3"). Empty inherits the policy minimum; an unknown
// non-empty value is rejected by the server with 400.
ConfinementClass string `json:"confinement_class,omitempty"`
// Interactive requests an interactive run: the sandbox comes up idle — or,
// with a non-empty Task, runs that boot seed in a persistent session — so a
// human can attach to it (wardyn attach <id>) either way. Pair with a
// never-reap policy (AutoStopAfterSec < 0) or the idle reaper will stop the
// idle sandbox.
Interactive bool `json:"interactive,omitempty"`
// WorkspaceID, when set, launches the run against that ONBOARDED workspace:
// the server prepends the workspace's stored source onto the resolved policy
// (a repo as a workspace_repos entry, a local dir as a read-only-by-default
// workspace_mounts entry) so the run inherits its approved egress, built image
// and bound model/harness credentials. Composes with PolicyID / InlinePolicy /
// the default policy — it seeds the source those cannot name without
// hand-reproducing the workspace's exact path. Container-kind workspaces are
// rejected: pass the image ref as Image instead.
WorkspaceID *uuid.UUID `json:"workspace_id,omitempty"`
// InlinePolicy, when set, supplies the run's full RunPolicySpec INLINE
// instead of referencing a stored PolicyID. It is MUTUALLY EXCLUSIVE with
// PolicyID (the server rejects both with 400); neither set falls back to the
// configured default. The server validates it exactly like a stored policy
// (mounts pass the same deny-list; api_key grants must reference an existing
// secret) and attaches it with no stored policy id.
InlinePolicy *RunPolicySpec `json:"inline_policy,omitempty"`
// DevcontainerRepo, when set AND an image builder is wired (WARDYN_ENVBUILD),
// triggers a devcontainer build of that git repo whose resulting image becomes
// the sandbox image. Ignored (degrades to the convention image) when no builder
// is wired. Mutually exclusive with Image.
DevcontainerRepo string `json:"devcontainer_repo,omitempty"`
// DevcontainerRef is the optional git ref (branch/tag/sha) to build for
// DevcontainerRepo.
DevcontainerRef string `json:"devcontainer_ref,omitempty"`
// Image, when set, is a USER-supplied base image (Bring Your Own Image); the
// server wraps it with the runner tools via a trusted finalize stage and
// requires an image builder to be wired (WARDYN_ENVBUILD) — an explicit
// Image with no builder wired is a hard 400 rather than a silent fallback.
// Mutually exclusive with DevcontainerRepo.
Image string `json:"image,omitempty"`
// TaskMode selects how a non-interactive run executes Task: "" / "harness"
// (default) runs the agent harness; "exec" runs Task as a plain shell
// command in the same governed sandbox (no agent, no LLM credentials — the
// BYOA/CI lane; see docs/CI.md). Ignored for an interactive run.
TaskMode string `json:"task_mode,omitempty"`
// InteractiveStart is TaskMode's interactive counterpart: what the attach
// shell opens with. "" / "shell" drops the human into a shell in the
// prepared workspace (the long-standing behavior); "agent" additionally
// launches the image's agent CLI (claude / codex) there, once, on the first
// attach. Request-scoped like TaskMode — never persisted on the run row,
// carried to the sandbox as WARDYN_INTERACTIVE_START and consumed by the
// image's attach ~/.bashrc. Ignored for a non-interactive run.
InteractiveStart string `json:"interactive_start,omitempty"`
// SeedAutoTools, when true, lets an interactive run's boot SEED (Task,
// interpreted per InteractiveStart — see Task's own doc) use tools before a
// human attaches, equivalent to --dangerously-skip-permissions for that
// pre-attach span only. Default false: the seed is supervised, so an
// unattended agent-started seed parks at its first tool-approval prompt
// until someone joins. Meaningful only for an agent-started seed with
// non-empty Task; request-scoped like InteractiveStart — never persisted on
// the run row, carried to the sandbox as WARDYN_SEED_AUTO_TOOLS.
SeedAutoTools bool `json:"seed_auto_tools,omitempty"`
// ToolApprovals governs an AUTONOMOUS (non-interactive) Claude Code run's
// own tool calls: "" / "auto" (default) is today's behavior — the sandbox
// and egress policy are the only boundary, same as
// --dangerously-skip-permissions; "hold" routes every tool call through
// Wardyn's approval FSM instead, so an operator decides each one before it
// runs. Rejected for codex-cli (no external tool-approval contract) and
// structurally inert for an interactive run (that run's own supervised-seed
// posture is SeedAutoTools's job, not this field's). Request-scoped like
// TaskMode — never persisted on the run row, carried to the sandbox as
// WARDYN_TOOL_APPROVALS.
ToolApprovals string `json:"tool_approvals,omitempty"`
// Workspaces carries PER-WORKSPACE options — which of a workspace's
// OPTIONAL requirements (types.Workspace.Requirements, level="optional")
// this run enables, and a read-only narrowing — for the workspaces this run
// attaches. Additive to WorkspaceID, which stays a working SINGLE-selection
// alias: a caller that sets only WorkspaceID (never touching Workspaces)
// gets exactly today's behavior — no optional requirement enabled, no
// narrowing. A REQUIRED requirement needs no entry here at all; it applies
// automatically whenever its workspace is used. A selection naming a
// workspace this run does not otherwise attach (via WorkspaceID or a
// policy's workspace_mounts/workspace_repos) does nothing.
Workspaces []WorkspaceSelection `json:"workspaces,omitempty"`
// IntegrationID, when set, pins this run's model/harness credential to a
// SPECIFIC AI-provider Integration (SiteConfig.Integrations[i].ID, stored
// or a well-known legacy-derived id — see GET /integrations), overriding
// any workspace LLMCred binding and the operator's DefaultFor:agent_runs
// default. Naming a non-AI-provider integration (a source-control or
// corporate-network id — those apply operator-wide already, and are never
// run-selectable) is a 400.
IntegrationID string `json:"integration_id,omitempty"`
}
CreateRunRequest is the body for POST /api/v1/runs.
type CreateRunResult ¶ added in v0.4.4
type CreateRunResult struct {
types.AgentRun
// Warnings are ADVISORY notices the server raised while resolving the run —
// discouraged, never blocking: a workspace-directory collision with another
// active run, or an ssh_key grant dropped because the agent has no SSH clone
// lane. Surface them: the run is live either way, so a dropped warning is a
// silently degraded run.
Warnings []string `json:"warnings,omitempty"`
}
CreateRunResult is the decoded POST /api/v1/runs 201 reply. AgentRun is EMBEDDED (the server puts the run's fields at the top level), so .ID/.State read straight off the result.
type CredentialGrant ¶
type CredentialGrant = types.CredentialGrant
CredentialGrant is a credential-grant eligibility record. Returned by ListGrants.
type DecisionOpts ¶ added in v0.5.0
type DecisionOpts struct {
// Scope is the decision's blast radius: ScopeOnce, ScopeRun (the zero
// value, and today's default), ScopeUntil, or ScopeAlways. Meaningful
// only for an egress_domain approval; the server rejects it otherwise.
Scope ApprovalScope
// Until is the expiry for Scope == ScopeUntil: required by the server in
// that case, and rejected if set for any other scope.
Until *time.Time
}
DecisionOpts is the optional scope/expiry for Approve/Deny. This repo has no WithX functional-option precedent (see ListOpts); DecisionOpts follows the same plain-struct-passed-variadically shape. Pass at most one.
type EgressRedirect ¶ added in v0.5.0
type EgressRedirect = types.EgressRedirect
EgressRedirect is one outbound redirect (package registry or otherwise), carried in SiteConfig.EgressRedirects. Aliased for the same reason as ArtifactOverride: GetSiteConfig returns a nil slice when unconfigured, so without a nameable element type a caller could not author one at all.
type GrantSpec ¶
GrantSpec is a credential scope description carried in RunPolicySpec.EligibleGrants.
type KillRunResponse ¶
KillRunResponse is the body returned by POST /api/v1/runs/{id}/kill.
type ListOpts ¶ added in v0.3.1
ListOpts carries the server's ?limit=&offset= pagination for the list and audit endpoints. The zero value sends nothing, so the server applies its default page size. Methods take it variadically; pass at most one.
type PolicyRequest ¶
type PolicyRequest struct {
Name string `json:"name"`
Spec types.RunPolicySpec `json:"spec"`
}
PolicyRequest is the body for POST/PUT /api/v1/policies. Name is required; Spec is validated server-side before persistence (a bad spec is rejected with 400, fail closed).
type PreflightItem ¶ added in v0.4.4
type PreflightItem struct {
Kind string `json:"kind"`
ID string `json:"id"`
Label string `json:"label"`
RequiredBy string `json:"required_by"`
Status string `json:"status"` // "satisfied" | "missing" | "unverified"
Detail string `json:"detail,omitempty"`
}
PreflightItem is one row of the preflight setup checklist: something the run needs, and whether it is already satisfied. Only the fields callers render are modeled — the full server row additionally carries a structured UI "fix" action and a credential-residency label.
type PreflightResult ¶ added in v0.4.4
type PreflightResult struct {
SetupItems []PreflightItem `json:"setup_items"`
EnforcedConfinementClass types.ConfinementClass `json:"enforced_confinement_class"`
// Warnings carries resolveRunPolicy's clamp notes — a member's silently
// narrowed inline policy, a filtered grant. The dry run is the ONLY place
// these surface (launch never returns them), so dropping them here left a
// member with no way to learn their policy was clamped at all.
Warnings []string `json:"warnings,omitempty"`
}
PreflightResult is the decoded POST /api/v1/runs/preflight reply: the setup checklist plus the confinement class the run would ACTUALLY enforce after the policy floor and blast-radius raise.
type ProfileResult ¶ added in v0.3.1
type ProfileResult struct {
Proposed struct {
InlinePolicy RunPolicySpec `json:"inline_policy"`
} `json:"proposed"`
OverallRisk string `json:"overall_risk"`
Observations struct {
Domains []struct {
Host string `json:"host"`
Methods []string `json:"methods"`
} `json:"domains"`
Anomalies []string `json:"anomalies"`
} `json:"observations"`
Warnings []string `json:"warnings"`
}
ProfileResult is the decoded POST /api/v1/runs/{id}/profile reply (Recording Mode): the synthesized least-privilege sandbox profile plus the observations it was built from. Only the fields callers render/save are modeled — the full server response (profileResponse) additionally carries a per-item risk breakdown the SDK does not surface.
type RecordTaskResult ¶ added in v0.3.1
type RecordTaskResult struct {
RecordRunID string `json:"record_run_id"`
TaskKey string `json:"task_key"`
Mode string `json:"mode"`
Detail string `json:"detail"`
Warnings []string `json:"warnings"`
}
RecordTaskResult is the decoded POST /api/v1/workspaces/{id}/record reply: the launched open-egress recording run plus the resolved session key/mode.
type RunPolicy ¶
RunPolicy is a declarative policy attached to runs. Returned by the policy methods (ListPolicies, GetPolicy, CreatePolicy, UpdatePolicy).
type RunPolicySpec ¶
type RunPolicySpec = types.RunPolicySpec
RunPolicySpec is the policy body carried in PolicyRequest.Spec. As a true `=` alias it carries the full wire surface, including AllowAllEgress (json:"allow_all_egress,omitempty") for the "allow all (deny-list only)" egress mode — no separate SDK struct to keep in sync.
type SiteConfig ¶ added in v0.4.4
type SiteConfig = types.SiteConfig
SiteConfig is the operator-wide site config. Returned by GetSiteConfig and accepted by PutSiteConfig.
type Source ¶ added in v0.5.0
Source is one tier-1 library entry: a repo/dir configured once (its own contract + scan) and attached to many workspaces.
type SourceKind ¶ added in v0.5.0
type SourceKind = types.SourceKind
SourceKind discriminates a library source: local_dir | repo.
type SourceRequest ¶ added in v0.5.0
type SourceRequest struct {
Kind types.SourceKind `json:"kind"`
// Locator is a host directory path (local_dir) or repo slug/clone URL (repo).
Locator string `json:"locator"`
// Ref is an optional git ref; repo only. Part of the identity — the same
// repo at two refs is two sources with two contracts.
Ref string `json:"ref,omitempty"`
Name string `json:"name,omitempty"`
// Requirements seeds the source's own contract (secret:/egress:/write:
// keys; integration: keys are tier-3-only and rejected here).
Requirements map[string]types.WorkspaceRequirement `json:"requirements,omitempty"`
}
SourceRequest is the body for POST /api/v1/sources — one repo/dir configured ONCE (its own requirements contract, its own scan profile) and attached to any number of workspaces. The server dedupes on canonical identity (kind, locator, ref): re-creating an existing source answers 200 with the existing row, contract and all, rather than a duplicate.
type Workspace ¶ added in v0.4.4
Workspace is an onboarded local dir / repo / container. Returned by ListWorkspaces, GetWorkspace, CreateWorkspace, and UpdateWorkspace.
type WorkspaceAttachment ¶ added in v0.5.0
type WorkspaceAttachment = types.WorkspaceAttachment
WorkspaceAttachment is one tier-3 composition row (Workspace.Attachments): either a library Source reference (SourceID set) or an inline ephemeral scratch row.
type WorkspaceBaseImage ¶ added in v0.5.0
type WorkspaceBaseImage = types.WorkspaceBaseImage
WorkspaceBaseImage is a Workspace's base-image choice, carried in WorkspaceRequest.BaseImage and returned in Workspace.BaseImage.
type WorkspaceBedrockRef ¶ added in v0.4.4
type WorkspaceBedrockRef = types.WorkspaceBedrockRef
WorkspaceBedrockRef is a Bedrock region/model selection. Aliased because it is a pointer-field shape a caller may need to build (dispatchParams. BedrockRef server-side); no current WorkspaceLLMCred field carries one — that binding resolves through an Integration (see WorkspaceLLMCred) — but the type is kept nameable for that resolution's future wiring.
type WorkspaceKind ¶ added in v0.4.4
type WorkspaceKind = types.WorkspaceKind
WorkspaceKind is what a workspace onboards (Workspace.Kind, WorkspaceRequest.Kind). Deprecated: a DERIVED READ-ONLY MIRROR of Workspace.Sources[0] (single-source only) — see WorkspaceSourceType for the field a multi-source Workspace actually carries per-source.
type WorkspaceLLMCred ¶ added in v0.4.4
type WorkspaceLLMCred = types.WorkspaceLLMCred
WorkspaceLLMCred is the operator-owned model/harness credential binding carried in WorkspaceRequest.LLMCred: IntegrationRef names a SiteConfig.Integrations entry this workspace's model/harness access resolves through. "" (or a nil WorkspaceLLMCred) means no binding.
type WorkspaceMount ¶
type WorkspaceMount = types.WorkspaceMount
WorkspaceMount is an operator/policy-controlled host bind mount carried in RunPolicySpec.WorkspaceMounts.
type WorkspaceRequest ¶ added in v0.3.1
type WorkspaceRequest struct {
Name string `json:"name"`
// Sources is the workspace's composition: one-or-more local_dir/repo/
// ephemeral sources. Mutually exclusive with the legacy scalar fields
// below (Kind/Source/Ref/DefaultTarget/Writable) — set one or the other,
// never both. Omitting both onboards the composition floor: one ephemeral
// scratch source.
Sources []types.WorkspaceSource `json:"sources,omitempty"`
// BaseImage is the workspace's base-image choice. Nil means the platform
// default convention image for the detected/scanned stack.
BaseImage *types.WorkspaceBaseImage `json:"base_image,omitempty"`
// Deprecated: Kind/Source/Ref/DefaultTarget/Writable are the pre-
// composition-model scalar shape — a single source, folded server-side
// into Sources[0] (legacyWorkspaceSource). Kept so
// `wardyn workspace create --kind local_dir --source /x` and existing SDK
// callers keep working; prefer Sources for a new caller, especially a
// multi-source one.
Kind types.WorkspaceKind `json:"kind,omitempty"`
Source string `json:"source,omitempty"`
Ref string `json:"ref,omitempty"`
DefaultTarget string `json:"default_target,omitempty"`
// Deprecated: see Kind. Writable opts the single legacy source into a
// READ-WRITE mount for import Record/Verify runs; omitted/false is
// read-only (the safe default). A sandboxed agent's changes then PERSIST
// to the host directory. A multi-source caller sets WorkspaceSource.Writable
// per source instead.
Writable bool `json:"writable,omitempty"`
// LLMCred is the operator-owned model/harness credential BINDING for this
// workspace/container (refs/names only). A run that picks the workspace
// inherits this model access. Nil => no binding. CREATE-ONLY: the update
// handler ignores it, so changing a binding needs the standalone
// PUT /workspaces/{id}/llm-cred route (not covered by this SDK).
LLMCred *types.WorkspaceLLMCred `json:"llm_cred,omitempty"`
}
WorkspaceRequest is the body for POST/PUT /api/v1/workspaces. Name is required, plus either Sources or the legacy scalar shape (Kind+Source); the server validates each source with the same deny-list the run path uses (local_dir bind-mount safety, repo slug/URL shape) before persisting.
internal/api aliases this type (`type workspaceRequest = client.WorkspaceRequest`) so server and SDK cannot drift; the server rejects unknown JSON fields, so a field missing here is unreachable from the SDK rather than merely undocumented.
type WorkspaceRequirement ¶ added in v0.5.0
type WorkspaceRequirement = types.WorkspaceRequirement
WorkspaceRequirement is one entry in Workspace.Requirements.
type WorkspaceSelection ¶ added in v0.5.0
type WorkspaceSelection struct {
// WorkspaceID is the workspace this selection applies to (string form of
// its uuid — matched against the run's referenced workspaces by id).
WorkspaceID string `json:"workspace_id"`
// EnabledOptional lists the workspace's OPTIONAL requirement KEYS (the
// exact "<type>:<key>" form, e.g. "egress:api.stripe.com" or
// "write:/home/user/repo") this run opts into. A key not listed here stays
// at its safe default (no egress, no grant, read-only mount).
EnabledOptional []string `json:"enabled_optional,omitempty"`
// ReadOnly, when set, NARROWS this workspace's write:<path> requirements —
// true forces every one read-only even if Required or enabled; false is a
// no-op (a selection may only narrow what the contract already grants,
// never widen it — see the fold in internal/api/runs_create.go). Nil
// leaves the contract's own resolved default in effect.
ReadOnly *bool `json:"read_only,omitempty"`
}
WorkspaceSelection is one per-run option set for an attached workspace. See CreateRunRequest.Workspaces.
type WorkspaceSource ¶ added in v0.5.0
type WorkspaceSource = types.WorkspaceSource
WorkspaceSource is one entry in a Workspace's composition, carried in WorkspaceRequest.Sources and returned in Workspace.Sources.
type WorkspaceSourceType ¶ added in v0.5.0
type WorkspaceSourceType = types.WorkspaceSourceType
WorkspaceSourceType discriminates a WorkspaceSource's kind (local_dir | repo | ephemeral).
type WorkspaceStatus ¶ added in v0.5.0
type WorkspaceStatus = types.WorkspaceStatus
WorkspaceStatus is the onboarding/scan lifecycle of a Workspace or Source (Workspace.Status, Source.Status): not-yet-scanned, mid-scan, scanned (ready to use), or errored.