- Add Warning field to HookResult
- runHookCmd sets Warning on timeout and start failure
- Hooks.Run collects warnings across commands
- All hook call sites emit warnings via infoEvent
- Test verifies timeout warning is surfaced
- Store = BlobStore + Open(name) (Store, error)
- BlobStore = ReadWriteStore + Delete, Create, Rename
- NewFlatDir/NewSkillStore return BlobStore (flat, no subdirectories)
- SessionStore/BatchStore satisfy Store via Open for child stores
- SessionFileStore/BatchJobStore embed *storeConfig, satisfy Store
- Replace SessionStore.SessionFileStore/BatchStore.JobStore with Open
- Add StoreEntry type alias for os.DirEntry
- SessionStore now owns construction of its child SessionFileStore
- Add SaveTranscript to SessionStoreConfig
- Server delegates to SessionStore instead of assembling the child
Move ReadableStore, WritableStore, ReadWriteStore, BlobStore, Store
interfaces and FlatDir (née FlatDirStore) implementation from 9p into
core so the agent runtime and other consumers can use them directly.
- Extract expandSystemPrompt(content, cwd) from loadSystemPrompt for
testability without file I/O
- Add tests: ListTools error, tools populated, TrustedTools injection,
agent prompt without system prompt, exec dispatch success/error/isError
- Add mockDispatcher and mockTrustedSetter test helpers
- Test all buildAnthropicMessages branches: system concat, assistant
tool-calls-only, nil arguments default, tool batching, unknown role,
full multi-turn conversation
- Test streamAnthropicSSE done re-entry: events after message_stop and
error are ignored
- Remove unreachable done guard in process closure
- Sink owns async writers and Flush; created once at startup
- Logger created via Sink.Logger/NewLogger/NewWriter
- agentCore.log field replaces package-level clog
- hooks.Run/runHookCmd accept *Logger parameter
- No globals, no init(). 100% test coverage.
- config.Load takes io.Reader, uses json.NewDecoder (100% coverage)
- skills package reduced to pure ParseFrontMatter(io.Reader) parser
- Filesystem operations moved to callers (9p/skillstore, agent/core)
- All tests use strings.NewReader — no temp files
- Add contract tests for tools.Server and tools.Dispatcher interfaces
(tools_test.go), covering all exported behavior including error paths.
pkg/tools coverage: 0% -> 100%.
- Add contract test for execute.Server (ListTools, CallTool), Decl
factory test, and executeElevated early-exit test. execute coverage:
68% -> 71%.
- Remove Close() from Server and Dispatcher interfaces and all
implementations/callers. These existed for MCP server cleanup which
has been removed.
- sandbox: remove dead code (DefaultConfig, Load/Save, LayeredConfig, Merge,
Version, SystemDefaults, validateName, ConfigPath, OpenSandbox); unexport
internal symbols; LoadSandbox now takes io.Reader; loadSandboxConfig owns
file opening; 83% package coverage via new sandbox_test.go
- backend: add BaseURL field to AnthropicBackend for testability; new
backend_test.go runs checkContract against all five implementations
(Ollama, OpenAI, Copilot, Anthropic, CodeWhisperer) via httptest servers
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Hook timeout configurable via hookTimeout var (unlocks <-timeout branch)
- newBackend injection into agentCore (unlocks /backend switch in tests)
- Remove dead code: WatchSignals, Prompt(), Goal(), isComplete/markComplete,
contextStatsString, extractMCPText, DefaultAgentsDir, DefaultSessionsDir,
Dispatcher() on AgentEnv
- Signal handling moved to process entry points; core has no OS signal knowledge
- Tests: extractMCPResult, mcpToolsToBackend, RestoreSession, SetEnv,
BuildAgentEnv, firstSentence, hook timeout, backend injection
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds tests for every slash command exposed through the session's ctl
file and direct r/w files (backend, model, agent, cwd). Each test pins
the exact behavioral guarantee 9P depends on: show-current, set-value,
error-while-running, empty-dir, current-item-marked, no-session guard.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Generating a new ID on /clear silently orphaned the 9P session directory.
Now /clear only nils the in-memory session; the ID (and its directory)
remain valid. The next turn overwrites the session file in place.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
setState("compacting") wraps session.compact() at both sites — manual
/compact (idle → compacting → idle) and auto-compact (thinking →
compacting → thinking). Tests capture state during the backend call to
verify the transition.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Concurrent Submit now unconditionally pushes to the FIFO rather than
trying pendingInject first. Use /i <prompt> to inject into the running
turn's tool-call loop, and /irw <prompt> to overwrite a pending inject.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tests cover the full agent turn lifecycle: happy path, state transitions
(idle→thinking→calling→idle), preTurn hook blocking and context injection,
postTurn hook continuation, FIFO drain, pendingInject as next turn,
interrupt mid-turn, manual and auto compaction, agentSpawn idempotency,
loadSystemPrompt panic on missing file, panic recovery in Submit, and
command dispatch (/help, /clear). Each test is a spec for a primitive the
9P layer and frontends depend on.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each slash command is now a closure in a map[string]cmdFn. Adding or
removing a command is a single map entry with no fall-through risk.
The ! shell handler is unchanged. handler(infoEvent("")) now fires only
for recognized commands, not unknown /foo inputs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Crash-left /tmp/ollie/{id}/ directories are now cleared once at process
start via sync.Once before the first session tmpdir is created.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both failures now panic with a descriptive message. Submit recovers,
logs the panic and stack trace via clog, cancels any in-progress action,
resets state to idle, and emits an error event to the handler.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Post-turn hook continue, unconsumed pendingInject, and FIFO drain all
previously re-entered Submit recursively, growing the stack with each
continuation. Replace with an explicit loop in Submit and extract the
single-turn logic into executeTurn, which returns the next prompt or "".
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
setState("idle") was called before handler(Event{Role:"newline"}),
meaning the final appendChat("\n") raced against statewait watchers
and clients that poll state. Remove the event entirely; clients no
longer see it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
context.AfterFunc callback was broadcasting without holding changeMu,
risking a missed wakeup if ctx cancels between the consumer's check
and cond.Wait(). Add unit tests covering the full state-change cycle
and the missed-wakeup race under -race.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
notifyChange must hold changeMu when broadcasting. Without the lock,
the broadcast can fire between the consumer's value check and its
cond.Wait call — the signal is lost and the consumer sleeps until the
next change, causing an apparent off-by-one lag.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a sync.Cond-based change notification mechanism. setState,
SetCWD, and usage updates all broadcast. WaitChange blocks until the
named field changes from the given current value, with context
cancellation support via context.AfterFunc.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
systemPrompt() loaded and templated files from DefaultPromptsDir() at
startup and on cwd change. This is now handled entirely by the
agentSpawn hook using the prime script, eliminating the parallel
prompt-injection path.
DefaultPromptsDir() is kept for the 9P server's p/ directory exposure.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Hook values can now be a string or array of strings in agent JSON config.
Commands run in order; exit 2 from any command blocks immediately.
Context from all successful commands is concatenated.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Allows wrapper scripts in ~/.config/ollie/scripts/x/ to shadow system
binaries transparently without modifying the user's shell environment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>