Agent V2 Design
Goal state for normalize @agent - autonomous coding agent.
Core Principles
- Do what's requested - no artificial limits on autonomy or scope
- Universal - CLI, IDE, CI all use the same agent
- Configurable - project-specific behavior via
[agent]config - Recoverable - retry → rollback → ask user escalation
Session Continuity
Agent can run indefinitely. When context fills or session ends:
- Summarize progress and open questions
- Write checkpoint to
.normalize/agent/session-<id>.json - New session picks up from checkpoint
Stops ONLY when:
- Blocked on design decisions (needs user input)
- Task is complete
- User explicitly stops
Validation Pipeline
Configurable in .normalize/config.toml - fully arbitrary schema:
[agent]
# User-defined validation - agent is just a Lua script, fully extensible
validate = ["typecheck", "test", "lint"]
validate_commands = [
{ name = "typecheck", run = "cargo check" },
{ name = "test", run = "cargo test" },
{ name = "lint", run = "cargo clippy" },
]
validate_on = "edit"
# Users can add any fields they want - agent.lua reads config freely
my_custom_option = "whatever"No predefined schema - agent is just Lua, users write their own if defaults don't fit.
Context Management
Commands the agent can use:
| Command | Effect |
|---|---|
$(keep N) | Retain output N in working memory |
$(note <fact>) | Record synthesized insight |
$(drop N) | Remove output N from context (NEW) |
$(forget <pattern>) | Remove notes matching pattern (NEW) |
Context is ephemeral by default - outputs shown once then gone unless kept.
Error Recovery
Escalation chain:
- Retry - same approach, maybe different parameters
- Rollback - undo to last known good state (shadow git)
- Ask user - blocked, need guidance
[error] cargo test failed
[retry 1/3] Running tests again...
[retry 2/3] Adjusting approach...
[retry 3/3] Final attempt...
[rollback] Reverting to pre-edit state
[blocked] Need help: tests still failing after rollback. Options:
1. Skip this test for now
2. Show me the test code
3. Explain what you were trying to doUser Input During Session
Problem: Claude Code often ignores user messages mid-task.
Solution:
- Acknowledge immediately - "Got it, will address after current step"
- Queue if unrelated - don't let unrelated input pollute task context
- Interrupt if urgent - keywords like "stop", "abort", "wait"
- Dispose after handling - unrelated queries don't persist in task context
Prompt pattern:
If user sends a message while you're working:
- If related to current task: incorporate immediately
- If unrelated: handle briefly, then return to task (don't add to task context)
- If "stop"/"abort"/"wait": pause and await further instructionIntegration Points
| Surface | How |
|---|---|
| CLI | normalize @agent "task" |
| IDE | Extension calls CLI, streams output |
| CI | normalize @agent --non-interactive --task-file tasks.md |
| MCP | Agent as MCP server for other tools |
Multi-Agent Coordination
Agents can spawn sub-agents for subtasks. Coordination required:
-- Parent spawns child for subtask
local child = agent.spawn("refactor auth module")
child:wait() -- blocks until child done
-- Or async with locks
local lock = agent.lock("src/auth/") -- claims ownership of path
-- ... do work ...
lock:release()Conflict avoidance:
- Locks - agent claims paths it's editing, siblings wait
- Pause - parent can pause children, siblings can request pause
- Queue - edits to locked paths queue until lock released
Lock granularity: configurable per-lock (agent decides based on task)
agent.lock("src/auth/")- directoryagent.lock("src/auth/jwt.rs")- fileagent.lock("src/auth/jwt.rs/verify")- symbol
Long-Term Memory
Short-term: $(keep), $(note), $(drop), $(forget) - within session
Long-term: memorize tool for cross-session persistence
memorize("auth module uses JWT tokens, see src/auth/jwt.rs")
memorize("user prefers functional style over OOP")
-- Stored in .normalize/memory/ (version controlled)
-- Accessible via recall()Memory storage: .normalize/memory/ directory, checked into git
facts.md- general project knowledgepreferences.md- user/team preferencesdecisions.md- past design decisions and rationale
Note: normalize init gitignore must NOT exclude .normalize/memory/ (unlike other .normalize/ contents)
Organization: both manual and LLM-assisted
- User can edit
.normalize/memory/*.mddirectly - Agent can reorganize/consolidate via LLM when prompted
normalize memory organize- LLM pass to dedupe/categorize
Implemented
- [x] Context commands: $(keep), $(note), $(drop), $(forget), $(memorize)
- [x] Session checkpoints: $(checkpoint), --resume, --list-sessions
- [x] Error escalation: retry → rollback → ask user (automatic after 3 failures)
- [x] Working memory IDs: random 4-char strings to avoid LLM autocomplete
- [x] Batch edit: $(batch-edit target1 action content | target2 action content)
- [x] Session logging: JSONL logs in .normalize/agent/logs/, --list-logs to view
- [x] Non-interactive mode: --non-interactive / -n for CI usage
Open Questions
- Parallel validation - shadow worktree configurable, default OFF (complexity vs benefit)
- Memory heuristics - what to auto-memorize vs explicit
memorizeonly? - Sub-agent error attribution - when validation fails, which sub-agent caused it? Need tracing/blame mechanism
Success Criteria
- Agent completes multi-file refactors without intervention
- Graceful degradation when stuck (clear error, options presented)
- Session continuity works (can resume after context fills)
- User input acknowledged and handled appropriately
- Works in CI (non-interactive mode)