unattended

package
v0.22.21 Latest Latest
Warning

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

Go to latest
Published: Apr 28, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package unattended implements ADR-023 phase 1: the --unattended flag, one-time per-repo disclosure, JSONL audit log, and the hard kill switch primitive.

Why a separate package: unattended-mode state crosses the CLI (argument parsing, disclosure prompt) and the supervisor (banner header, audit emit on every dispatch). Centralising it here keeps both surfaces calling one canonical implementation — the trust file, the audit path resolver, the banner formatter — and makes the policy testable in isolation.

What this package DOESN'T do (deferred to v1.1, per ADR-023):

  • Self-paced wake-up scheduling (`ScheduleWakeup` integration)
  • Watch-event resumption (PR merged, CI failed, file changed)
  • The compounding-trust clamp around remote A2A peers — that lands when ADR-024 phase 1 (Agent Card endpoint) ships

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AuditDir

func AuditDir(sessionID string) string

AuditDir returns the per-session audit directory: $XDG_DATA_HOME/clawtool/sessions/<id>/, or ~/.local/share/clawtool/sessions/<id>/ when XDG isn't set.

func DisclosurePanel

func DisclosurePanel(repoPath string) string

DisclosurePanel returns the operator-facing copy printed on the first --unattended invocation per repo. Lists every downstream flag clawtool will set so the operator confirms knowingly.

Per ADR-023: the disclosure is the flag name + this panel + the audit log. We do NOT add modal popups inside long-running sessions; that's the author's anti-pattern call.

func Grant

func Grant(repoPath, note string) error

Grant adds a trust row for repoPath. Idempotent — re-granting updates GrantedAt but doesn't duplicate.

func IsTrusted

func IsTrusted(repoPath string) (bool, error)

IsTrusted reports whether the operator has previously granted unattended-mode trust to this repo path. Lookup is exact-match on RepoPath after filepath.Clean — symlinks NOT resolved (we trust the operator's CLI invocation path).

func Revoke

func Revoke(repoPath string) (bool, error)

Revoke removes the trust row. ok=false when the path wasn't in the file.

func TrustFilePath

func TrustFilePath() string

TrustFilePath returns the canonical path: $XDG_DATA_HOME/clawtool/ unattended-trust.toml, or ~/.local/share/clawtool/unattended- trust.toml when XDG isn't set.

Types

type AuditEntry

type AuditEntry struct {
	TS       time.Time      `json:"ts"`
	Session  string         `json:"session_id"`
	Kind     string         `json:"kind"`            // "dispatch" | "result" | "rule_block" | "kill"
	Agent    string         `json:"agent,omitempty"` // instance name when relevant
	Family   string         `json:"family,omitempty"`
	Prompt   string         `json:"prompt,omitempty"` // truncated to ~256 chars
	Result   string         `json:"result,omitempty"` // truncated tail
	Error    string         `json:"error,omitempty"`
	Metadata map[string]any `json:"metadata,omitempty"`
}

AuditEntry is one line in the JSONL audit log. The schema is intentionally append-only: new fields are additive, never renamed, so an operator can grep across logs from older clawtool versions without a parser break.

type SessionState

type SessionState struct {
	ID        string    `json:"session_id"`
	StartedAt time.Time `json:"started_at"`
	RepoPath  string    `json:"repo_path"`
	AuditPath string    `json:"audit_path"`
	YOLOAlias bool      `json:"yolo_alias,omitempty"` // true when the operator invoked --yolo
	// contains filtered or unexported fields
}

SessionState carries the live unattended-mode session. Every dispatch in unattended mode runs through one of these so the audit log + banner ride together without the supervisor having to thread state through opts.

func Begin

func Begin(repoPath string, yolo bool) (*SessionState, error)

Begin creates a new SessionState with a fresh UUID and audit log path. Caller MUST defer Close on the returned state so the audit file flushes to disk on session end.

func (*SessionState) Banner

func (s *SessionState) Banner() string

Banner returns the persistent status line the supervisor renders on every dispatch result so callers downstream of the dispatch know the chain crossed an unattended boundary. Format mirrors ADR-023 §Behaviour.

func (*SessionState) Close

func (s *SessionState) Close() error

Close flushes and closes the audit file. Safe to call multiple times.

func (*SessionState) Emit

func (s *SessionState) Emit(e AuditEntry)

Emit appends one entry to the session's audit log. Failures silently log to stderr — losing an audit line shouldn't kill the dispatch, but operators should know the audit broke.

type TrustEntry

type TrustEntry struct {
	RepoPath  string    `toml:"repo_path"`
	GrantedAt time.Time `toml:"granted_at"`
	Note      string    `toml:"note,omitempty"`
}

TrustEntry is one row in the per-repo trust file. The operator confirms once per repo path; subsequent unattended dispatches from the same path skip the disclosure.

Jump to

Keyboard shortcuts

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