- system prompt gains a Project workflow block when the repo tracks its own
progress (TODO.md/ROADMAP.md/docs): read the task list first and keep it
current, spec-first for non-trivial work, complete unit tests, verify before
declaring done
- TODO.md + ROADMAP.md loaded as 'Project tracker' instruction blocks, capped
tighter than AGENTS.md so the agent sees the shape without drowning in it
- one soft nudge per session when a turn writes files without touching the
task list; suppressed when todo_write was called; never a gate
- /workflow command + panel showing TODO/ROADMAP/docs presence, line/file
counts, nudge state
- config: workflow.enabled (default true), workflow.docsDir (default docs)
- prompt-cache version key extended with wf: so toggling the workflow busts
the cached system prompt
- docs: docs/workflow.md, configuration table row, ROADMAP + TODO entries
- tests: test/workflow.test.ts (9 tests)
830 tests pass, typecheck clean, build green, live headless demo verified
- /changes diffs the last turn's file snapshot (added/modified/deleted), reusing undo infra via SnapshotStack.peek()
- system prompt memoized behind version counters (notebook/memory/skills/plugins/tools/workspace); hit-rate in /cost, foundation for provider caching
- web_search: DuckDuckGo Lite, keyless, 5 results, SSRF-filtered, in the net set with ask permission
- /search <query>: full-text grep over saved sessions incl. tool-input JSON
- workspace file list re-walks at a turn boundary after writes
- maxSpendPerTurn: per-turn cap stops a runaway step with a notice
- /fork: branch the session at the last turn boundary, original untouched
821 tests pass, typecheck clean, build green
walk() at boot -> Session.workspaceFiles -> systemPrompt Environment
section + subagent system prompts. read_many_files still on-demand,
but the agent now sees the tree without a tool call.
walk({includeDirs}) yields src/ and src/ui/ with trailing slash, only
on the @ path. matchPaths ranks dirs before files for the same prefix
so @src/ surfaces the directory itself. Insertion keeps the slash.
File tools record before-write state via snapshot hook; Session
captures beforeFiles at turn start and afterFiles at turn end (cap
100 via SnapshotStack), and undo/redo restore files + messages
together. Bash not snapshotted (docs + notice).
task now accepts { description, prompt, kind } or
{ tasks: TaskSpec[], kind? } (up to 8) and fans out with
Promise.all. Each subagent keeps its own context window and
the progress panel receives start/step/result/end per id, so
independent searches overlap in wall time instead of queueing.
- src/subagent.ts: runOne extracted, createTaskTool uses union
schema (single | batch), batch validates worker channel once
then Promise.all, results joined as headings.
- docs/agents.md: delegation section notes tasks batch.
- 800 pass (added subagent-parallel.test.ts).
- mcpExpose=phi|direct|auto on RawConfig + MCPConfig; phi default keeps
direct as a measured option for small servers (2-tool cheaper direct)
- src/mcp.ts: buildMcpMetaTools + phi branch in connectMcp: lazy
list/inspect/call behind 3 fixed schemas instead of N per-tool schemas;
direct branch kept; bindMcpGuard wires permission+PluginHost guard for
MCP calls through the same gate as built-ins
- prompt mcpServers names-only under phi; under direct schemas travel
as before — 20-tool server ~2750 tok -> ~phi (names) until mcp_call
- session: isDirect mcpServerNames non-enumerable marker, activeTools
hides mcp_call from pre-wired rules when inside mcp_call, /tools
shows mcp_call and Enabled/Withheld reflects the 3 meta-names under phi
- permission: mcp_* as read (free), mcp_call mutating keyed by
server.tool, same top-level suppression + ask-to-approve as other
mutating tools
- cli: bindMcpGuard + /mcp list shows exposure + mcp_* listed;
headless denies line mentions mcp_list
- commit.ts: git_commit_message kept in git set via toolSetOf/
disabledToolNames overlay
Tests: 798 pass, 0 fail; tsc exit 0; mcp.test.ts covers phi stays
empty until mcp_call and direct still namespaced.
Wrap every builtin tool with withMeta({set, mutating}) at its definition
site (src/tool-utils.ts). TOOL_SETS and MUTATING_TOOLS are now derived
via setsFrom/mutatingNames rather than hand-lists, so a new write cannot
be added ungated by forgetting a parallel list. Permission defaults now
cover the 5 extra mutating line-edit tools. Test suite covers coverage,
derived-equality, and mutating consistency (test/tool-derive.test.ts).
Summarize pruned span: droppedSpan + summarizeDiscarded (6k excerpt,
3-6 lines, one call per compaction) with retained note already landed;
flip TODO Now checkboxes to [x].
Hot-reload: Session.updateSkills/updatePlugins with pendingSkills/
pendingHost deferred during a turn, drainPendingHotReload at turn
boundary, live skill tool closure, cli.tsx rebuilds host from
builtin+registry+external on /registry add/remove. Guard now uses
live pluginHost. Test mid-session skill callability and plugin
enforcement without restart.
Spec: .hermes/plans/todo-now-next.md
- Implement global memory layer for cross-project patterns.
- Improve memory entry scoring with recency and tokenization.
- Adjust MAX_TEXT limit from 400 to 800 for better context retention.
- Add TTL pruning for stale memory entries.
- Capture and summarize dropped content during compaction.
- Update tests to reflect changes in memory behavior and compaction logic.
Keeps local claude-code preset (readClaudeCodeSettings from ~/.claude/settings.json) merged with upstream Pickers refactor.
Resolved Onboard.tsx: both readClaudeCodeSettings + Frame/Row imports.