schemas

package
v0.16.1 Latest Latest
Warning

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

Go to latest
Published: May 10, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package schemas defines the typed payload structs for every `--json`-emitting bones CLI verb (ADR 0053). Each verb has one Go struct here; the `cmd/bones-schemagen` binary reflects these structs and writes derived JSON Schema files into the repo-root `schemas/` directory.

Go types in this package are the source of truth for the external `--json` contract. Types here are intentionally separate from the internal storage types under `internal/tasks`, `internal/swarm`, etc.; the duplication pins the external surface so internal types can evolve freely behind it.

The envelope below is universal: every emitter wraps its payload in `Envelope[T]` so consumers can write one parser that handles every verb. The single carve-out (`bones logs --json`, which passthrough-emits substrate event-log NDJSON) is documented in ADR 0053 and uses the substrate's own contract per ADR 0052.

Index

Constants

This section is empty.

Variables

View Source
var Verbs = []VerbInfo{
	{Verb: "doctor", CurrentVersion: "v1", PayloadName: "DoctorAllPayload"},
	{Verb: "status", CurrentVersion: "v1", PayloadName: "StatusAllPayload"},
	{Verb: "swarm.dispatch", CurrentVersion: "v1", PayloadName: "SwarmDispatchPayload"},
	{Verb: "swarm.status", CurrentVersion: "v1", PayloadName: "SwarmStatusPayload"},
	{Verb: "swarm.tasks", CurrentVersion: "v1", PayloadName: "SwarmTasksPayload"},
	{Verb: "tasks.aggregate", CurrentVersion: "v1", PayloadName: "TasksAggregatePayload"},
	{Verb: "tasks.bySlot", CurrentVersion: "v1", PayloadName: "TasksBySlotPayload"},
	{Verb: "tasks.claim", CurrentVersion: "v1", PayloadName: "TasksClaimPayload"},
	{Verb: "tasks.close", CurrentVersion: "v1", PayloadName: "TasksClosePayload"},
	{Verb: "tasks.create", CurrentVersion: "v1", PayloadName: "TasksCreatePayload"},
	{Verb: "tasks.link", CurrentVersion: "v1", PayloadName: "TasksLinkPayload"},
	{Verb: "tasks.list", CurrentVersion: "v2", PayloadName: "TasksListPayload"},
	{Verb: "tasks.prime", CurrentVersion: "v1", PayloadName: "TasksPrimePayload"},
	{Verb: "tasks.ready", CurrentVersion: "v1", PayloadName: "TasksReadyPayload"},
	{Verb: "tasks.show", CurrentVersion: "v1", PayloadName: "TasksShowPayload"},
	{Verb: "tasks.update", CurrentVersion: "v1", PayloadName: "TasksUpdatePayload"},
	{Verb: "up", CurrentVersion: "v1", PayloadName: "UpPayload"},
	{Verb: "workspaces.get", CurrentVersion: "v1", PayloadName: "WorkspacesGetPayload"},
	{Verb: "workspaces.list", CurrentVersion: "v1", PayloadName: "WorkspacesListPayload"},
}

Verbs is the canonical registry. Order is alphabetical by verb name; the generator iterates this slice and writes schemas/<verb>.<version>.json per entry.

When adding a new verb: append an entry here, define the payload struct below, run `make schemas`, and add the per-verb test in cli/schemas_test.go.

Functions

func Emit

func Emit[T any](w io.Writer, env Envelope[T]) error

Emit marshals env as compact JSON to w with a trailing newline. Mirrors the pre-existing `emitJSON` helper's wire shape so a `--json`-emitting verb wrapped by this helper byte-for-byte matches the pre-envelope shape (modulo the wrap).

Compact output is the bones default; emitters that previously used indented output (`json.NewEncoder.SetIndent`) keep their indented shape via EmitIndent. A future v2 may unify these, but v1 pins today's per-verb shape.

func EmitIndent

func EmitIndent[T any](w io.Writer, env Envelope[T]) error

EmitIndent marshals env as indented (2-space) JSON to w with a trailing newline emitted by the encoder. Used by verbs whose pre-envelope shape was `json.NewEncoder.SetIndent(""," ")` — `swarm.status`, `workspaces.list`, `workspaces.get` — so v1 preserves their human-readable indentation.

func VersionFor

func VersionFor(verb string) string

VersionFor returns the current version string for verb. Falls back to "v1" for unknown verbs so the generator and emitters share one lookup. (CI gates that every emitter's verb is in this registry, so the fallback only fires on coding errors.)

Types

type DoctorAllPayload

type DoctorAllPayload struct {
	Workspaces []DoctorWorkspaceRow `json:"workspaces"`
}

DoctorAllPayload is the payload for `bones doctor --all --json`. Mirrors the per-workspace row shape `renderDoctorAllJSON` emits.

type DoctorWorkspaceRow

type DoctorWorkspaceRow struct {
	Name     string `json:"name"`
	Cwd      string `json:"cwd"`
	HubAlive bool   `json:"hub_alive"`
	Issues   int    `json:"issues"`
}

DoctorWorkspaceRow is one row of the doctor --all summary.

type Edge

type Edge struct {
	Type   string `json:"type"`
	Target string `json:"target"`
}

Edge mirrors the on-the-wire edge shape from internal/tasks.Edge. Re-declared here so cli/schemas owns the external contract; the internal Edge type may evolve behind it.

type Envelope

type Envelope[T any] struct {
	Schema Schema `json:"schema"`
	Data   T      `json:"data"`
}

Envelope wraps every `--json` payload. T is the verb-specific typed payload struct defined elsewhere in this package.

Generic over T so the compiler enforces that the wrapped payload matches what the schemagen generator reflected for the named verb; a copy/paste mismatch (wrapping a TasksListPayload under a schema verb of "tasks.show") becomes a build error.

func New

func New[T any](verb, version string, data T) Envelope[T]

New builds an Envelope[T] with the given verb name, version string, and typed payload. Used by every emitter so the schema block is constructed in one place — no emitter spells out the verb-name or version-tag literal twice.

type Schema

type Schema struct {
	Verb    string `json:"verb"`
	Version string `json:"version"`
}

Schema is the meta-block stamped on every bones `--json` emit. Verb is the dotted CLI command path (e.g. "tasks.list", "swarm.dispatch"). Version is "v" followed by an integer (e.g. "v1"); the ADR 0053 hard-cut migration policy means a single version of bones emits exactly one version per verb.

type StatusAllPayload

type StatusAllPayload struct {
	Workspaces []StatusWorkspaceRow `json:"workspaces"`
}

StatusAllPayload is the payload for `bones status --all --json`. Mirrors `renderStatusAllJSON`: live registry rows only.

type StatusWorkspaceRow

type StatusWorkspaceRow struct {
	Cwd       string             `json:"cwd"`
	Name      string             `json:"name"`
	HubURL    string             `json:"hub_url"`
	State     string             `json:"state"`
	Sessions  int                `json:"sessions"`
	StartedAt timefmt.LoggedTime `json:"started_at"`
}

StatusWorkspaceRow is one row of the status --all view.

State (#305) is one of "active" (live hub, PID alive + HTTP probe ok), "idle" (PID=0, registered by `bones up` but no hub serving), or "paused" (PID > 0 but probe failed). Scripts branching on the row should match this field rather than reading HubPID directly.

type SwarmDispatchPayload

type SwarmDispatchPayload struct {
	ManifestPath string `json:"manifest_path"`
	TaskCount    int    `json:"task_count"`
	PlanSHA256   string `json:"plan_sha256"`
}

SwarmDispatchPayload is the payload for `bones swarm dispatch --json`. Mirrors `dispatchSummaryJSON`: manifest path + plan hash + task count for the just-built dispatch.

type SwarmStatusPayload

type SwarmStatusPayload []SwarmStatusRow

SwarmStatusPayload is the payload for `bones swarm status --json`. Mirrors `[]statusRow` — every active swarm-session record.

type SwarmStatusRow

type SwarmStatusRow struct {
	Slot         string             `json:"slot"`
	TaskID       string             `json:"task_id"`
	AgentID      string             `json:"agent_id"`
	Host         string             `json:"host"`
	LeafPID      int                `json:"leaf_pid"`
	StartedAt    timefmt.LoggedTime `json:"started_at"`
	LastRenewed  timefmt.LoggedTime `json:"last_renewed"`
	State        string             `json:"state"`
	StaleSeconds int64              `json:"stale_seconds"`
}

SwarmStatusRow is one swarm-session row.

type SwarmTasksPayload

type SwarmTasksPayload []Task

SwarmTasksPayload is the payload for `bones swarm tasks --json`. Mirrors the `[]tasks.Task` shape returned by the slot-scoped readiness filter.

type Task

type Task struct {
	ID            string              `json:"id"`
	Title         string              `json:"title"`
	Status        string              `json:"status"`
	ClaimedBy     string              `json:"claimed_by,omitempty"`
	Files         []string            `json:"files"`
	Parent        string              `json:"parent,omitempty"`
	Edges         []Edge              `json:"edges,omitempty"`
	Context       map[string]string   `json:"context,omitempty"`
	CreatedAt     timefmt.LoggedTime  `json:"created_at"`
	UpdatedAt     timefmt.LoggedTime  `json:"updated_at"`
	DeferUntil    *timefmt.LoggedTime `json:"defer_until,omitempty"`
	ClosedAt      *timefmt.LoggedTime `json:"closed_at,omitempty"`
	ClosedBy      string              `json:"closed_by,omitempty"`
	ClosedReason  string              `json:"closed_reason,omitempty"`
	ClaimEpoch    uint64              `json:"claim_epoch,omitempty"`
	OriginalSize  uint64              `json:"original_size,omitempty"`
	CompactLevel  uint8               `json:"compact_level,omitempty"`
	CompactedAt   *timefmt.LoggedTime `json:"compacted_at,omitempty"`
	SchemaVersion int                 `json:"schema_version"`
	LastEventSeq  uint64              `json:"last_event_seq,omitempty"`
}

Task is the on-the-wire shape every task-emitting verb writes. Mirrors internal/tasks.Task field-for-field including JSON tags (`omitempty` markers preserved); see ADR 0005 and ADR 0014 for the canonical schema.

Per #324 every time field is timefmt.LoggedTime so the marshal path emits UTC RFC3339 rather than RFC3339Nano-with-local-offset. Pointer-time fields stay pointer-typed so an absent value omits cleanly under omitempty rather than serializing the zero value.

type TasksAggregatePayload

type TasksAggregatePayload struct {
	Since       string               `json:"since"`
	TotalTasks  int                  `json:"total_tasks"`
	TotalSlots  int                  `json:"total_slots"`
	ActiveSlots int                  `json:"active_slots"`
	Slots       []TasksAggregateSlot `json:"slots"`
}

TasksAggregatePayload is the payload for `bones tasks aggregate --json`. Mirrors `aggregateResult`: window summary + per-slot breakdown.

type TasksAggregateSlot

type TasksAggregateSlot struct {
	SlotID string   `json:"slot_id"`
	Tasks  int      `json:"tasks"`
	Files  []string `json:"files"`
	Status string   `json:"status"`
}

TasksAggregateSlot is the per-slot summary row inside a tasks.aggregate payload.

type TasksBySlotPayload

type TasksBySlotPayload struct {
	Slots        []TasksSlotGroup `json:"slots"`
	HotThreshold int              `json:"hot_threshold"`
}

TasksBySlotPayload is the payload for `bones tasks list --by-slot --json`. Distinct verb name from `tasks.list` because the shape diverges: `tasks.list` emits `[]Task`; `tasks.bySlot` emits a per-slot grouping with the hot-threshold context.

type TasksClaimPayload

type TasksClaimPayload = Task

TasksClaimPayload is the payload for `bones tasks claim --json`. Emits the post-claim Task record.

type TasksClosePayload

type TasksClosePayload = Task

TasksClosePayload is the payload for `bones tasks close --json`. Emits the post-close Task record.

type TasksCreatePayload

type TasksCreatePayload = Task

TasksCreatePayload is the payload for `bones tasks create --json`. Emits the just-created Task record.

type TasksLinkPayload

type TasksLinkPayload struct {
	From string `json:"from"`
	To   string `json:"to"`
	Type string `json:"type"`
}

TasksLinkPayload is the payload for `bones tasks link --json`. Emits a link-confirmation tuple.

type TasksListPayload

type TasksListPayload struct {
	Tasks []Task `json:"tasks"`
}

TasksListPayload is the payload for `bones tasks list --json`. Emits a (possibly filtered) list of tasks. Default-mode list only; the `--by-slot` mode emits the `tasks.bySlot` shape instead.

v2 (#NNN): wrapped the array in a named field for shape consistency with every other envelope (`status`, `workspaces.list`, `swarm.status`, etc., all use `data.<resource>`). v1 returned the array as `data` directly. Consumers using `.data[]` against v1 migrate to `.data.tasks[]` against v2.

type TasksPrimePayload

type TasksPrimePayload struct {
	OpenTasks    []TasksPrimeTask     `json:"open_tasks"`
	ReadyTasks   []TasksPrimeTask     `json:"ready_tasks"`
	ClaimedTasks []TasksPrimeTask     `json:"claimed_tasks"`
	Threads      []TasksPrimeThread   `json:"threads"`
	Peers        []TasksPrimePresence `json:"peers"`
}

TasksPrimePayload is the payload for `bones tasks prime --json`. Mirrors `primeResultJSON`: the agent's open/ready/claimed task view + recent threads + online peers.

type TasksPrimePresence

type TasksPrimePresence struct {
	AgentID   string             `json:"agent_id"`
	Project   string             `json:"project"`
	StartedAt timefmt.LoggedTime `json:"started_at"`
	LastSeen  timefmt.LoggedTime `json:"last_seen"`
}

TasksPrimePresence is the peer-presence row inside a tasks.prime payload.

type TasksPrimeTask

type TasksPrimeTask struct {
	ID        string             `json:"id"`
	Title     string             `json:"title"`
	Files     []string           `json:"files,omitempty"`
	ClaimedBy string             `json:"claimed_by,omitempty"`
	CreatedAt timefmt.LoggedTime `json:"created_at"`
	UpdatedAt timefmt.LoggedTime `json:"updated_at"`
}

TasksPrimeTask is the trimmed task shape used inside a tasks.prime payload — coord.Task projection without storage-internal fields.

type TasksPrimeThread

type TasksPrimeThread struct {
	ThreadShort  string             `json:"thread_short"`
	LastActivity timefmt.LoggedTime `json:"last_activity"`
	MessageCount int                `json:"message_count"`
	LastBody     string             `json:"last_body"`
}

TasksPrimeThread is the chat-thread row inside a tasks.prime payload.

type TasksReadyPayload

type TasksReadyPayload []Task

TasksReadyPayload is the payload for `bones tasks ready --json`. Always emits an array (never null); empty result yields `[]`.

type TasksShowPayload

type TasksShowPayload = Task

TasksShowPayload is the payload for `bones tasks show --json`. Single Task record.

type TasksSlotGroup

type TasksSlotGroup struct {
	Slot      string   `json:"slot"`
	OpenCount int      `json:"open_count"`
	Hot       bool     `json:"hot"`
	TaskIDs   []string `json:"task_ids"`
}

TasksSlotGroup is one slot's grouping row.

type TasksUpdatePayload

type TasksUpdatePayload = Task

TasksUpdatePayload is the payload for `bones tasks update --json`. Post-update Task record (or pre-update record when the update was a no-op).

type UpAction

type UpAction struct {
	Category string `json:"category"`
	Action   string `json:"action"`
	Target   string `json:"target"`
	From     string `json:"from,omitempty"`
	To       string `json:"to,omitempty"`
}

UpAction is one structured action `bones up` performed during this invocation. Category is one of the pinned set (gitignore, hooks, skills, manifest); Action is the verb (added, refreshed, installed, rewrote, synced, bumped); Target is the object (gitignore entry, hook event + command, skill count, schema version stamp).

From / To are populated only for `rewrote` actions — the legacy command and the canonical replacement, respectively. They are `omitempty` so non-rewrite rows don't carry empty string noise.

type UpPayload

type UpPayload struct {
	Actions []UpAction `json:"actions"`
	Summary UpSummary  `json:"summary"`
}

UpPayload is the payload for `bones up --json` (issue #314). Mirrors the per-action structured output emitted on the human path, plus a summary block carrying the workspace path and total action count so the envelope is self-describing.

The shape is generic over action category — `gitignore`, `hooks`, `skills`, `manifest` — to keep the typed wire surface stable as future actions enter the categories. Adding a brand-new category is intentional friction (per the issue's trap-3 guidance) but requires no schema change here.

type UpSummary

type UpSummary struct {
	Workspace   string `json:"workspace"`
	ActionCount int    `json:"action_count"`
}

UpSummary is the trailing summary block of an UpPayload. Mirrors the human-path success signature emitted via uxprint.Up: workspace path + action count.

type VerbInfo

type VerbInfo struct {
	Verb           string
	CurrentVersion string
	// PayloadName is the Go type name of the payload struct,
	// matched against the schemagen reflector's output. Lets the
	// generator drive entirely off this slice instead of walking
	// the AST.
	PayloadName string
}

Verb identifies one CLI emit site. The dotted name matches the command path (`tasks.list` ↔ `bones tasks list`); CurrentVersion is the version this binary emits.

All verbs start at "v1" per ADR 0053's hard-cut migration policy.

type WorkspacesGetPayload

type WorkspacesGetPayload = WorkspacesRow

WorkspacesGetPayload is the payload for `bones workspaces show <name> --json`. Single registry row.

type WorkspacesListPayload

type WorkspacesListPayload []WorkspacesRow

WorkspacesListPayload is the payload for `bones workspaces ls --json`. All registry rows in the deterministic sort order ListInfo applies.

type WorkspacesRow

type WorkspacesRow struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Cwd         string `json:"cwd"`
	HubStatus   string `json:"hub_status"`
	LastTouched string `json:"last_touched"`
	AgentID     string `json:"agent_id"`
	NATSURL     string `json:"nats_url"`
	HubURL      string `json:"hub_url"`
}

WorkspacesRow is one registry entry as serialized by both `workspaces.list` and `workspaces.get`.

Jump to

Keyboard shortcuts

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