knight

package
v1.1.71 Latest Latest
Warning

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

Go to latest
Published: May 1, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package knight implements the background auto-evolution agent. Knight runs during idle time in daemon mode, analyzing sessions, creating and validating skills, generating tests, and maintaining project health.

Index

Constants

This section is empty.

Variables

View Source
var ErrLockConflict = fmt.Errorf("knight: another instance already running in this workspace")

ErrLockConflict is returned by Start when another ggcode instance in the same project directory already holds the Knight lock. Callers can check this to show a user-facing hint without treating it as a real error.

Functions

func CheckDuplicate

func CheckDuplicate(entry *SkillEntry, existing []*SkillEntry) bool

CheckDuplicate returns true if a skill with similar name already exists.

func FormatLockMessage added in v1.1.57

func FormatLockMessage(pid int) string

FormatLockMessage returns a human-readable message about why Knight didn't start.

func FormatSkillRefForDisplay

func FormatSkillRefForDisplay(scope, name string) string

FormatSkillRefForDisplay returns the canonical scope-qualified skill reference.

func LockHeldBy added in v1.1.57

func LockHeldBy(projDir string) (int, error)

LockHeldBy returns the PID of the process holding the Knight lock for the given project directory, or 0 if the lock is not held.

Types

type AgentFactory

type AgentFactory func(systemPrompt string, maxTurns int, onUsage func(provider.TokenUsage)) (AgentRunner, error)

AgentFactory creates a Knight agent with restricted tools. The onUsage callback receives token usage after each LLM call.

type AgentRunner

type AgentRunner interface {
	RunStream(ctx context.Context, prompt string, onEvent func(provider.StreamEvent)) error
}

AgentRunner is the interface Knight uses to run LLM-powered tasks. It mirrors subagent.AgentRunner for compatibility.

type AnalysisResult

type AnalysisResult struct {
	SessionsAnalyzed int
	SkillCandidates  []SkillCandidate
}

AnalysisResult holds the outcome of a session analysis.

type Budget

type Budget struct {
	// contains filtered or unexported fields
}

Budget tracks daily token consumption for Knight.

func NewBudget

func NewBudget(dir string, cfg config.KnightConfig) *Budget

NewBudget creates a Budget tracker. Data is stored under dir/knight/.

func (*Budget) CanSpend

func (b *Budget) CanSpend() bool

CanSpend returns true if Knight has enough remaining budget to start a task.

func (*Budget) DailyLimit

func (b *Budget) DailyLimit() int

DailyLimit returns the configured daily budget.

func (*Budget) EnsureDir

func (b *Budget) EnsureDir() error

EnsureDir creates the knight data directory if needed.

func (*Budget) Record

func (b *Budget) Record(task string, inputTokens, outputTokens int) error

Record adds a token usage entry to today's log.

func (*Budget) Remaining

func (b *Budget) Remaining() int

Remaining returns how many tokens are left in today's budget.

func (*Budget) Used

func (b *Budget) Used() int

Used returns today's total token consumption.

type CandidateQueue

type CandidateQueue struct {
	// contains filtered or unexported fields
}

CandidateQueue persists deferred high-value skill candidates between runs.

func NewCandidateQueue

func NewCandidateQueue(path string) *CandidateQueue

NewCandidateQueue creates a queue backed by the given JSON file path.

func (*CandidateQueue) EnsureDir

func (q *CandidateQueue) EnsureDir() error

EnsureDir creates the parent directory for the queue file.

func (*CandidateQueue) List

func (q *CandidateQueue) List() ([]SkillCandidate, error)

List returns the current deferred candidates sorted by priority.

func (*CandidateQueue) Remove

func (q *CandidateQueue) Remove(candidate SkillCandidate) error

Remove deletes a candidate from the queue if present.

func (*CandidateQueue) Upsert

func (q *CandidateQueue) Upsert(candidate SkillCandidate) error

Upsert stores or updates a deferred candidate.

type Emitter

type Emitter interface {
	EmitKnightReport(report string)
	HasTargets() bool
}

Emitter is the interface Knight uses to send IM notifications.

type EventSink added in v1.1.53

type EventSink interface {
	// OnTaskStart is called when a Knight task begins.
	OnTaskStart(taskName string)
	// OnTaskComplete is called when a Knight task finishes with a detailed report.
	OnTaskComplete(taskName string, report string, duration time.Duration)
}

EventSink receives Knight task lifecycle events for display in TUI/daemon.

type FuncSink added in v1.1.53

type FuncSink struct {
	OnStart    func(taskName string)
	OnComplete func(taskName string, report string, duration time.Duration)
}

FuncSink is an EventSink that delegates to callback functions.

func (*FuncSink) OnTaskComplete added in v1.1.53

func (s *FuncSink) OnTaskComplete(taskName string, report string, duration time.Duration)

func (*FuncSink) OnTaskStart added in v1.1.53

func (s *FuncSink) OnTaskStart(taskName string)

type Knight

type Knight struct {
	// contains filtered or unexported fields
}

Knight is the background auto-evolution agent. It runs scheduled tasks during idle time, analyzes sessions, creates and validates skills.

func New

func New(cfg config.KnightConfig, homeDir, projDir string, store session.Store) *Knight

New creates a new Knight instance.

func (*Knight) BudgetStatus

func (k *Knight) BudgetStatus() (used int, remaining int, limit int)

BudgetStatus returns current Knight token usage counters.

func (*Knight) CanPerformTask

func (k *Knight) CanPerformTask() bool

CanPerformTask checks if Knight has budget and is allowed to run.

func (*Knight) FindActiveSkill

func (k *Knight) FindActiveSkill(ref string) (*SkillEntry, error)

FindActiveSkill resolves an active skill reference, optionally scoped as project:name or global:name.

func (*Knight) FindStagingSkill

func (k *Knight) FindStagingSkill(ref string) (*SkillEntry, error)

FindStagingSkill resolves a staging skill reference, optionally scoped as project:name or global:name.

func (*Knight) Index

func (k *Knight) Index() *SkillIndex

Index returns the skill index for external access.

func (*Knight) NotifyActivity

func (k *Knight) NotifyActivity()

NotifyActivity is called when the user sends a message, resetting the idle timer.

func (*Knight) PerformSkillAnalysis

func (k *Knight) PerformSkillAnalysis(ctx context.Context) error

PerformSkillAnalysis triggers an immediate skill analysis task.

func (*Knight) PerformSkillValidation

func (k *Knight) PerformSkillValidation(ctx context.Context) ([]ValidationResult, error)

PerformSkillValidation validates all active skills.

func (*Knight) PromoteStaging

func (k *Knight) PromoteStaging(skillName string) error

PromoteStaging promotes a staging skill to active after validation.

func (*Knight) Queue added in v1.1.54

func (k *Knight) Queue() *CandidateQueue

Queue returns the candidate queue for external queries.

func (*Knight) RecordSkillEffectiveness

func (k *Knight) RecordSkillEffectiveness(ref string, score int)

RecordSkillEffectiveness records a 1-5 effectiveness score for a skill.

func (*Knight) RecordSkillUse

func (k *Knight) RecordSkillUse(ref string)

RecordSkillUse increments the usage counter for a skill. Called from the skill tool when a Knight-managed skill is loaded.

func (*Knight) RejectStaging

func (k *Knight) RejectStaging(skillName string) error

RejectStaging removes a staging skill.

func (*Knight) RollbackSkill

func (k *Knight) RollbackSkill(name string) error

RollbackSkill restores the latest snapshot for an active skill.

func (*Knight) RunAdhocTask

func (k *Knight) RunAdhocTask(ctx context.Context, goal string) (TaskResult, error)

RunAdhocTask executes a user-directed Knight task using the configured agent factory.

func (*Knight) RunTask

func (k *Knight) RunTask(ctx context.Context, taskName, prompt string, factory AgentFactory) TaskResult

RunTask executes a single Knight task with budget tracking and default maxTurns=10. Token usage is tracked via the onUsage callback wired into the agent.

func (*Knight) RunTaskWithTurns added in v1.1.53

func (k *Knight) RunTaskWithTurns(ctx context.Context, taskName, prompt string, factory AgentFactory, maxTurns int) TaskResult

RunTaskWithTurns executes a single Knight task with a custom maxTurns limit.

func (*Knight) Running

func (k *Knight) Running() bool

Running returns whether Knight is currently active.

func (*Knight) SetEmitter

func (k *Knight) SetEmitter(e Emitter)

SetEmitter sets the IM emitter for Knight notifications.

func (*Knight) SetEventSink added in v1.1.53

func (k *Knight) SetEventSink(s EventSink)

SetEventSink sets the event sink for task lifecycle notifications.

func (*Knight) SetFactory

func (k *Knight) SetFactory(f AgentFactory)

SetFactory sets the agent factory for LLM-powered tasks.

func (*Knight) SetSkillFrozen

func (k *Knight) SetSkillFrozen(name string, frozen bool) error

SetSkillFrozen updates an active skill's frozen flag.

func (*Knight) SkillFeedback

func (k *Knight) SkillFeedback(ref string) (avgScore float64, samples int)

SkillFeedback returns runtime feedback stats for a skill.

func (*Knight) SkillUsage

func (k *Knight) SkillUsage(ref string) (count int, lastUsed time.Time, avgScore float64)

SkillUsage returns runtime usage stats for a skill.

func (*Knight) Start

func (k *Knight) Start(ctx context.Context) error

Start begins the Knight background loop.

func (*Knight) Status

func (k *Knight) Status() string

Status returns a human-readable status string.

func (*Knight) Stop

func (k *Knight) Stop()

Stop gracefully shuts down Knight.

type Promoter

type Promoter struct {
	// contains filtered or unexported fields
}

Promoter handles moving skills from staging to active directories.

func NewPromoter

func NewPromoter(homeDir, projectDir string) *Promoter

NewPromoter creates a skill promoter.

func (*Promoter) Promote

func (p *Promoter) Promote(entry *SkillEntry) error

Promote moves a skill from staging to the active skills directory. It creates a snapshot of any existing skill with the same name for rollback.

func (*Promoter) Reject

func (p *Promoter) Reject(entry *SkillEntry) error

Reject removes a skill from staging.

func (*Promoter) Rollback

func (p *Promoter) Rollback(entry *SkillEntry) error

Rollback restores the most recent snapshot for an active skill.

func (*Promoter) WriteStaging

func (p *Promoter) WriteStaging(name, scope, content string) (string, error)

WriteStaging writes a new skill to the appropriate staging directory.

type SessionAnalyzer

type SessionAnalyzer struct {
	// contains filtered or unexported fields
}

SessionAnalyzer analyzes session history to discover reusable patterns.

func NewSessionAnalyzer

func NewSessionAnalyzer(k *Knight) *SessionAnalyzer

NewSessionAnalyzer creates a session analyzer.

func (*SessionAnalyzer) AnalyzeRecent

func (sa *SessionAnalyzer) AnalyzeRecent(ctx context.Context) (*AnalysisResult, error)

AnalyzeRecent scans recent sessions for high-value learning signals.

Filtering and priority:

  1. Only sessions matching the current project workspace are analyzed.
  2. Sessions already analyzed in previous ticks are skipped (dedup).
  3. Sessions are prioritized: corrections/failure-fixes first, then recency.
  4. Up to `limit` sessions are analyzed per tick.

func (*SessionAnalyzer) CollectProjectConventions

func (sa *SessionAnalyzer) CollectProjectConventions() string

CollectProjectConventions reads well-known project config files for context.

func (*SessionAnalyzer) GenerateSkillFromAnalysis

func (sa *SessionAnalyzer) GenerateSkillFromAnalysis(ctx context.Context, candidate SkillCandidate, factory AgentFactory) (string, error)

GenerateSkillFromAnalysis uses LLM to create a skill from a high-value candidate. The skill is a behavioral guideline that teaches the AI what to do (or not do) based on real user interactions.

func (*SessionAnalyzer) RecordUsage

func (sa *SessionAnalyzer) RecordUsage(usage provider.TokenUsage)

RecordUsage records token usage for session analysis tasks.

type SkillCandidate

type SkillCandidate struct {
	Name           string
	Description    string
	Scope          string // "global" or "project"
	Score          float64
	Reason         string
	EvidenceCount  int
	SourceSessions []string
	// Evidence holds the key conversation excerpts that justify this skill.
	// For corrections: [0]=what AI did wrong, [1]=what user said instead.
	// For failure-fix: [0]=error message, [1]=how it was fixed.
	Evidence []string
	// Category classifies the skill source for LLM context.
	Category string // "correction", "failure-fix", "convention"
	// GenFailCount tracks consecutive LLM generation failures; abandon after knightMaxGenFailures.
	GenFailCount int `json:",omitempty"`
}

SkillCandidate is a potential skill discovered from session analysis.

type SkillEntry

type SkillEntry struct {
	Name     string
	Meta     SkillMeta
	Path     string // full path to the skill file
	Scope    string // "global" or "project"
	Staging  bool   // true if in staging directory
	LoadedAt time.Time
}

SkillEntry is a discovered skill with its metadata and file location.

type SkillIndex

type SkillIndex struct {
	// contains filtered or unexported fields
}

SkillIndex scans and indexes skills from both global and project directories. Results are cached with a TTL to avoid repeated disk reads.

func NewSkillIndex

func NewSkillIndex(homeDir, projectDir string) *SkillIndex

NewSkillIndex creates a skill index for the given home and project dirs.

func (*SkillIndex) ActiveSkills

func (si *SkillIndex) ActiveSkills() ([]*SkillEntry, error)

ActiveSkills returns only active (non-staging) skills.

func (*SkillIndex) Directories

func (si *SkillIndex) Directories() []string

Directories returns all skill directories for display purposes.

func (*SkillIndex) FindActiveByName

func (si *SkillIndex) FindActiveByName(name string) *SkillEntry

FindActiveByName finds an active skill by name.

func (*SkillIndex) Invalidate

func (si *SkillIndex) Invalidate()

Invalidate clears the cache, forcing a fresh scan on next access.

func (*SkillIndex) Scan

func (si *SkillIndex) Scan() ([]*SkillEntry, error)

Scan returns all discovered skills (active + staging), using cache when fresh.

func (*SkillIndex) StagingSkills

func (si *SkillIndex) StagingSkills() ([]*SkillEntry, error)

StagingSkills returns only staging skills.

type SkillMeta

type SkillMeta struct {
	Name                string   `yaml:"name"`
	Description         string   `yaml:"description"`
	Scope               string   `yaml:"scope"` // "global" or "project"
	Platforms           []string `yaml:"platforms"`
	Requires            []string `yaml:"requires"`
	CreatedBy           string   `yaml:"created_by"`   // "user", "knight", "agent"
	CreatedFrom         string   `yaml:"created_from"` // source session ID
	CreatedAt           string   `yaml:"created_at"`
	UpdatedAt           string   `yaml:"updated_at"`
	UsageCount          int      `yaml:"usage_count"`
	LastUsed            string   `yaml:"last_used"`
	EffectivenessScores []int    `yaml:"effectiveness_scores"`
	Frozen              bool     `yaml:"frozen"`
}

SkillMeta is the parsed frontmatter from a SKILL.md or staging skill file.

type TaskResult

type TaskResult struct {
	TaskName string
	Output   string
	Tokens   provider.TokenUsage
	Duration time.Duration
	Error    error
}

TaskResult holds the outcome of a Knight task execution.

type UsageTracker

type UsageTracker struct {
	// contains filtered or unexported fields
}

UsageTracker tracks skill usage for Knight's lifecycle management. Persists to a JSON file in the project's .ggcode/ directory. Uses a dirty flag to batch disk writes — only saves when data changed and at most once per writeInterval.

func NewUsageTracker

func NewUsageTracker(path string) *UsageTracker

NewUsageTracker creates a usage tracker that persists to the given path.

func (*UsageTracker) AllUsage

func (ut *UsageTracker) AllUsage() map[string]skillUsage

AllUsage returns a snapshot of all usage data.

func (*UsageTracker) EnsureDir

func (ut *UsageTracker) EnsureDir() error

EnsureDir creates the parent directory for the usage file.

func (*UsageTracker) Flush

func (ut *UsageTracker) Flush()

Flush persists dirty data to disk. Called periodically by the scheduler.

func (*UsageTracker) GetFeedback

func (ut *UsageTracker) GetFeedback(name string) (avgScore float64, samples int)

GetFeedback returns the average effectiveness score and sample count.

func (*UsageTracker) GetUsage

func (ut *UsageTracker) GetUsage(name string) (count int, lastUsed time.Time, avgScore float64)

GetUsage returns usage data for a skill.

func (*UsageTracker) IsStale

func (ut *UsageTracker) IsStale(name string, threshold time.Duration) bool

IsStale returns true if a skill hasn't been used for the given duration.

func (*UsageTracker) RecordEffectiveness

func (ut *UsageTracker) RecordEffectiveness(name string, score int)

RecordEffectiveness adds an effectiveness score (1-5) for a skill.

func (*UsageTracker) RecordUse

func (ut *UsageTracker) RecordUse(name string)

RecordUse increments the usage count and updates last_used for a skill.

func (*UsageTracker) Snapshot

func (ut *UsageTracker) Snapshot(name string) (skillUsage, bool)

type ValidationResult

type ValidationResult struct {
	Valid    bool     `json:"valid"`
	Errors   []string `json:"errors,omitempty"`
	Warnings []string `json:"warnings,omitempty"`
}

ValidationResult contains the outcome of skill validation.

func ValidateSkill

func ValidateSkill(entry *SkillEntry) ValidationResult

ValidateSkill runs all validation checks on a skill entry.

Jump to

Keyboard shortcuts

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