dream

package
v0.3.1 Latest Latest
Warning

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

Go to latest
Published: Aug 2, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Overview

Package dream implements background memory consolidation: when the session goes idle, a restricted subagent reorganizes the auto-memory directory — merging duplicates, fixing stale facts, pruning the MEMORY.md index.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	MemoryDir   string // config.MemoryDir(cwd)
	SessionsDir string // config.SessionsDir(cwd)
	Settings    config.DreamSettings
	// CurrentSession returns the active session ID so the session gate can
	// exclude it (its transcript mtime is always fresh). May be nil.
	CurrentSession func() string
	// TaskRT registers the run so /tasks shows it and can kill it.
	TaskRT *task.Runtime
	// Runner executes the dream agent; a private subagent.Runner so
	// the run never touches the main agent (no notify, no follow-up).
	Runner agentRunner
	// Watcher records the memory files a run touched, for the completion
	// notice. Comes from BuildAgentConfig; nil gets an inert one.
	Watcher *Watcher
}

Config wires a Dreamer into the host session. Directories are injected (rather than derived from cwd here) so tests never touch the real ~/.codebot tree.

type Dreamer

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

Dreamer triggers background memory consolidation. MaybeStart is the idle-hook entry (gated), StartManual the /dream entry (immediate). The lock file is the cross-process guard; `running` the in-process one.

func New

func New(cfg Config) *Dreamer

func (*Dreamer) MaybeStart

func (d *Dreamer) MaybeStart()

MaybeStart runs the auto-trigger gates, cheapest first: enabled (no IO), in-process running flag, time gate (one stat), scan throttle. The session gate does directory IO, so it runs on a goroutine off the event path.

func (*Dreamer) SetOnDone added in v0.3.1

func (d *Dreamer) SetOnDone(fn func(files []string, err error))

SetOnDone installs the completion callback. Set here rather than in Config because the UI that renders the notice is built after the Dreamer.

func (*Dreamer) StartManual

func (d *Dreamer) StartManual() (taskID string, err error)

StartManual triggers a consolidation immediately (/dream), skipping the time, throttle, and session gates. The lock still applies: it is what prevents two concurrent runs across processes.

type Lock

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

Lock is a file lock whose mtime doubles as the last-consolidation timestamp: acquiring writes the holder PID (pushing mtime to now), a successful run simply keeps that mtime, and a failed run rewinds it so the time gate reopens.

func NewLock

func NewLock(memoryDir string) *Lock

func (*Lock) Complete

func (l *Lock) Complete()

Complete marks a successful run: the PID body is cleared so this process no longer counts as a holder (a manual /dream may re-run immediately), and the fresh mtime becomes lastConsolidatedAt for the auto time gate.

func (*Lock) LastConsolidatedAt

func (l *Lock) LastConsolidatedAt() time.Time

LastConsolidatedAt returns the lock file's mtime, or the zero time when no consolidation has ever run. Cost: one stat.

func (*Lock) Rollback

func (l *Lock) Rollback(prior time.Time)

Rollback rewinds the lock to its pre-acquire state after a failed or killed run, reopening the time gate. A zero prior restores "never consolidated" (file removed). The PID body is cleared — this process is still alive and would otherwise look like a holder. Errors are swallowed: the worst case is the next trigger waiting a full MinHours again.

func (*Lock) TryAcquire

func (l *Lock) TryAcquire() (prior time.Time, ok bool)

TryAcquire attempts to take the lock. On success it returns the pre-acquire mtime (for Rollback) and true; the file now holds this process's PID with mtime = now, which is all a successful run needs — no separate completion stamp.

It yields (returns false) when another live process acquired within the last hour. A dead PID, an unparseable body, or an mtime older than an hour (PID-reuse guard) is reclaimed. After writing, the body is re-read to break ties between two concurrent reclaimers: the loser bails.

type Watcher added in v0.3.1

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

Watcher records which memory files a run wrote to, so the completion notice can name them. Without it a dream leaves no trace the user will see — the task entry in /tasks is somewhere nobody looks.

One Watcher is shared by the agent config and the Dreamer: runs are serialized by the lock and the running flag, so a single reset-then-collect cycle is enough.

func BuildAgentConfig

func BuildAgentConfig(cwd string, model agentcore.ChatModel, ctxFactory func(agentcore.ChatModel) agentcore.ContextManager, sessionID string) (subagent.Config, *Watcher)

BuildAgentConfig assembles the restricted dream agent. It deliberately bypasses AgentDefinition/BuildToolPool: the definition registry would expose dream to the main model's subagent tool, and the shared pool cannot interpose the path guard. The subagent loop has no approval gate, so the tool set IS the security boundary: read-only exploration plus write/edit confined to the memory directory, and no bash at all. The returned Watcher records which memory files the run touched; hand it to dream.Config so the completion notice can name them. Returned rather than accepted so there is no way to wire a different instance into each half and silently observe nothing.

func NewWatcher added in v0.3.1

func NewWatcher() *Watcher

Jump to

Keyboard shortcuts

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