ajhahn.de
← eeco
Go 82 lines
// Package cockpit is eeco's neutral, harness-independent model of an AI
// cockpit and the renderers that translate it into harness-specific
// config. A Playbook is a single unit of AI procedure — what it does, the
// structured safety contract it must never violate, the capabilities it is
// allowed, the ordered steps, and the output it produces. The model is
// brand-free; a Renderer (one per harness) is the only thing that knows a
// target's file layout and permission spelling.
//
// The single product-defining guarantee lives here, not in the renderer:
// the safety invariant (ScanAllowlistForWriteGitVerbs, gate.go) is derived
// from the structured Intent, so an emitted artifact can never grant a
// write-capable git verb a Playbook declares forbidden. Generation refuses
// rather than silently drop a forbidden verb.
//
// Dependency direction is fixed to avoid an import cycle: cockpit owns the
// model + renderer + gate + ledger + orchestration; internal/playbooks
// imports cockpit for the Playbook type; cmd/eeco wires the two
// (playbooks.Get -> cockpit.Generate). cockpit never imports playbooks.
package cockpit

// Playbook is the neutral, harness-independent description of one AI
// procedure. The same Playbook renders to any harness target; only a
// Renderer knows a target's file layout and permission spelling.
type Playbook struct {
	Name           string       `json:"name"`                         // skill dir + frontmatter name
	Description    string       `json:"description"`                  // single-line: when + what + safety promise
	Intent         Intent       `json:"intent"`                       // structured safety contract
	Capabilities   []Capability `json:"capabilities"`                 // ordered allowlist source
	Steps          []Step       `json:"steps"`                        // ordered procedure (Step 0..N)
	OutputFormat   string       `json:"output_format"`                // closing body section
	Params         []Param      `json:"params,omitempty"`             // optional parameterization
	MapsToWorkflow string       `json:"maps_to_workflow,omitempty"`   // deterministic backing (metadata only in C1)
}

// Intent is the structured safety contract. Forbidden seeds the prose
// warning the renderer derives; ForbiddenGitVerbs is the gate's denylist
// (falling back to defaultForbiddenGitVerbs when empty). The renderer
// derives both the allowlist and the warning from this — neither is ever
// hand-written into the body data.
type Intent struct {
	Guarantee         string   `json:"guarantee"`                       // positive promise (prose seed)
	Forbidden         []string `json:"forbidden"`                       // human phrases, e.g. "git commit", "touch any tracked file"
	ForbiddenGitVerbs []string `json:"forbidden_git_verbs,omitempty"`   // git write/mutate denylist (gate input)
}

// forbiddenVerbs returns the git write/mutate denylist the gate scans
// against: the Playbook's own list when set, otherwise the package default.
func (in Intent) forbiddenVerbs() []string {
	if len(in.ForbiddenGitVerbs) > 0 {
		return in.ForbiddenGitVerbs
	}
	return defaultForbiddenGitVerbs
}

// Capability is one entry of the allowlist source. Kind is "tool" (a named
// harness tool) or "bash" (a shell command head with an optional arg
// scope). The renderer walks Capabilities in declared order — the JSON is
// the single source of truth, so there is no silent reorder or dedupe.
type Capability struct {
	Kind  string `json:"kind"`            // "tool" | "bash"
	Name  string `json:"name,omitempty"`  // tool name when kind="tool"
	Verb  string `json:"verb,omitempty"`  // command head when kind="bash" ("git status", "date")
	Scope string `json:"scope,omitempty"` // arg glob when kind="bash"; default "*"
}

// Step is one ordered instruction. Runs lists optional read-only commands
// shown in a fenced block under the step body.
type Step struct {
	Index int      `json:"index"`
	Title string   `json:"title"`
	Body  string   `json:"body"`
	Runs  []string `json:"runs,omitempty"`
}

// Param is one optional parameter the procedure accepts. Reserved for the
// parameterized-general playbooks (C2); unused by the C1 handover source.
type Param struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Default     string `json:"default,omitempty"`
}