Summary
Add a first-class /goal command to DeerFlow, modeled after Claude Code's goal feature: a user sets a verifiable completion condition, DeerFlow runs the lead agent, and after each completed turn a separate lightweight evaluator decides whether the condition is satisfied. If not, DeerFlow automatically starts the next continuation turn with the evaluator reason as guidance. If yes, the goal is cleared/recorded as achieved.
This should be implemented as a thread/session-level completion contract, not as a skill and not as a stronger prompt inside the main agent.
External reference
Claude Code's documented behavior is the reference design:
/goal sets a completion condition and keeps the current session running across turns until that condition is met.
- After each turn, a small fast model evaluates the condition against the surfaced conversation evidence.
- A failed evaluation starts another turn and feeds the evaluator reason back as guidance.
- A successful evaluation clears the goal and records the achieved entry.
- One goal can be active per session;
/goal shows status; /goal clear and aliases cancel it.
- The evaluator does not run tools or read files independently, so conditions should be written as verifiable outcomes the agent can demonstrate in the transcript.
- The implementation is described as a session-scoped prompt-based Stop hook.
References:
Motivation
DeerFlow already supports long-running agent work, plan mode, todos, subagents, sandboxed execution, thread persistence, and streaming. However, users still need to manually decide when to send the next prompt for long-horizon work. A Claude Code-style /goal gives DeerFlow a higher-level workflow primitive:
- "Keep working until this check passes."
- "Continue triaging this queue until it is empty."
- "Implement this design until these acceptance criteria hold."
- "Refactor this module until the file-size/test constraints are satisfied."
The important distinction is that completion is judged by a separate evaluator at run finalization time, not by the same agent that is doing the work.
Current DeerFlow fit
Useful existing pieces:
ThreadState already persists structured state such as todos, artifacts, and title through the checkpointer.
TodoMiddleware already gives multi-step progress visibility when is_plan_mode is true.
SkillActivationMiddleware already owns /skill-name ... semantics, so /goal must be a reserved built-in command, not a skill.
- The TUI already has a pure built-in slash command registry in
backend/packages/harness/deerflow/tui/command_registry.py.
- Web submission flows through
frontend/src/components/workspace/input-box.tsx and frontend/src/core/threads/hooks.ts.
- Gateway runs funnel through
app.gateway.services.create_run_record_and_task() and deerflow.runtime.runs.worker.run_agent().
run_agent() has a finalization point after success/error/interruption, token usage persistence, title sync, thread-meta status update, and bridge.publish_end().
RunManager.create_or_reject() already serializes active runs per thread and supports reject/interrupt/rollback strategies.
Proposed behavior
Command semantics
Add /goal as a built-in command across Web, TUI, and eventually IM/headless clients.
Supported forms:
/goal <condition>: set or replace the active goal, then immediately start a turn using the condition as the directive.
/goal: show active goal status, or the most recently achieved/cleared goal for the current thread/session.
/goal clear: clear the active goal without marking it achieved.
- Aliases for clear:
stop, off, reset, none, cancel.
Initial non-goals:
- Do not support multiple concurrent goals per thread.
- Do not make
/goal a DeerFlow skill.
- Do not let the main agent self-certify completion with a tool call.
- Do not let the evaluator run arbitrary tools in v1.
Thread state
Extend ThreadState with a reducer-backed goal channel. Suggested shape:
class GoalState(TypedDict, total=False):
id: str
condition: str
status: Literal["active", "achieved", "cleared", "failed"]
created_at: str
updated_at: str
achieved_at: str | None
cleared_at: str | None
clear_reason: str | None
evaluated_turns: int
continuation_turns: int
consecutive_blocks: int
token_baseline: int
token_spend: int
last_evaluated_run_id: str | None
last_decision: Literal["pass", "fail", "error"] | None
last_reason: str | None
last_guidance: str | None
Reducer semantics should mirror merge_todos: None preserves existing goal state; an explicit goal update replaces it.
Questions for implementation:
- Should achieved/cleared goals remain in checkpoint state for
/goal status, or move to run/thread metadata after completion?
- Should Web threads treat goals as thread-scoped, while TUI/CLI treat them as session-scoped with counters reset on resume?
Recommended v1 answer: persist the active goal in ThreadState so Web, TUI, and Gateway agree. Keep the latest achieved/cleared entry in the same state for status display. Revisit a historical goal log later.
Slash command ownership
Add goal to RESERVED_SLASH_SKILL_NAMES in deerflow.skills.slash so /goal cannot be interpreted as /goal skill activation.
Create a shared command parser rather than duplicating Web/TUI behavior:
- Move or mirror TUI command registry concepts into a reusable harness module, e.g.
deerflow.commands.registry.
- Built-ins:
goal, help, new, resume, etc.
- Skills remain dynamically appended as slash-skill activations.
- Web autocomplete should list
/goal as a built-in command alongside enabled skills.
Goal run flow
The core loop should live outside the agent graph, near run finalization:
- User submits
/goal <condition>.
- Gateway creates/updates
ThreadState.goal as active.
- Gateway starts a normal lead-agent run with the condition as the user directive.
- The lead agent runs with normal tools, skills, todos, sandbox, memory, and subagents.
run_agent() reaches finalization with status success.
- A Goal coordinator checks whether the thread has an active goal and whether this run should be evaluated.
- The coordinator collects bounded evidence from the completed run and current checkpoint state.
- The evaluator model returns structured JSON: pass/fail/error + reason + optional next guidance.
- If pass: update
goal.status=achieved, store reason, publish a goal event, and leave thread idle.
- If fail: update
goal.last_reason, increment counters, and enqueue one continuation run with a hidden/system control prompt containing the reason.
- If evaluation fails or continuation limits trip: mark goal failed or pause it with a visible reason rather than looping indefinitely.
The continuation run should use multitask_strategy="reject" and should only be scheduled after the completed run fully exits, so it does not race the previous run's checkpoint writes.
Evaluator
Introduce deerflow.runtime.goals.evaluator or similar.
Inputs:
- Goal condition.
- Recent visible transcript, including the latest user/AI turn.
- Tool summaries or run events from the latest run.
- Current todos and their statuses.
- Artifacts written during the run.
- Token/turn counters.
- The evaluator's previous reason, if any.
Output schema:
{
"ok": true,
"reason": "The transcript shows `pytest backend/tests/test_goal.py` exited 0 and the goal condition only required that check."
}
or
{
"ok": false,
"reason": "The implementation changed backend files, but no test result has been surfaced yet.",
"guidance": "Run the relevant backend tests and surface the exact command and exit status."
}
The evaluator should use a configured small/fast model, similar in spirit to Claude Code defaulting goal evaluation to the configured small fast model. DeerFlow can follow existing patterns from title generation and suggestions:
goals:
enabled: true
evaluator_model_name: null # null = default model, can be overridden
max_condition_chars: 4000
max_consecutive_blocks: 8
max_continuation_turns: 20
max_eval_context_messages: 20
max_eval_context_chars: 24000
require_trusted_workspace: false # future: relevant for local/TUI hook-like behavior
The evaluator should not call tools in v1. This keeps it cheap and avoids giving an automated stop-condition checker its own side effects. A later v2 could add an agent-based verifier, but only with explicit config and limits.
Continuation prompt
Continuation prompts should be hidden from normal chat UI but persisted enough for reproducibility. Example content:
<goal_continuation>
Active goal: {condition}
The previous turn did not satisfy the goal.
Evaluator reason: {reason}
Guidance for the next turn: {guidance}
Continue working toward the active goal. Surface concrete evidence for any checks you run.
</goal_continuation>
Display rules:
- Hide raw control messages from the normal transcript, like slash-skill activation reminders.
- Show compact goal status/event rows: active, evaluator reason, continuing, achieved, cleared, failed.
- Ensure memory extraction ignores hidden goal-control messages unless explicitly useful.
Safety and loop limits
Borrow the same failure posture as Claude Code Stop hooks:
- Cap consecutive failed evaluator blocks, default 8.
- Cap total continuation turns, default configurable.
- Do not continue after a run error, interruption, rollback, or safety termination unless explicitly configured.
- Do not continue while another run is pending/running for the same thread.
- User input wins: if a user submits a new message while a goal continuation is being considered, do not auto-schedule over it.
- Do not continue if there are unresolved clarification interrupts.
- Do not continue if active background subagents/tool tasks are still running and their output has not returned.
- Publish a visible warning when the cap trips, including the last evaluator reason.
Frontend
Add a GoalProgressRow or GoalPanel near the composer, parallel to the existing To-do panel.
It should show:
- Active condition.
- Runtime duration.
- Evaluated turn count.
- Token spend since activation or resume baseline.
- Latest evaluator reason.
- Actions: clear/cancel, possibly copy condition.
Web command UX:
- Autocomplete
/goal as a built-in slash command.
- Submitting
/goal <condition> should not be sent as a literal user-visible task if the backend command API can set the state directly; alternatively, v1 can submit the condition as the user directive but mark the slash command metadata for display cleanup.
/goal status should open/show the goal panel or append a compact status message.
/goal clear should call a goal API and update thread state without starting a normal agent turn.
APIs
Possible Gateway endpoints:
GET /api/threads/{thread_id}/goal
PUT /api/threads/{thread_id}/goal with { condition }
DELETE /api/threads/{thread_id}/goal
- Optional:
POST /api/threads/{thread_id}/goal/evaluate for tests/debug only.
However, the LangGraph-compatible path still needs to surface goal updates through thread state snapshots so the existing useStream frontend state model works.
Backend integration points
Recommended module placement:
backend/packages/harness/deerflow/agents/thread_state.py: GoalState, merge_goal, goal field.
backend/packages/harness/deerflow/commands/: shared slash command registry and parser.
backend/packages/harness/deerflow/runtime/goals/: goal evaluator, coordinator, prompt builder, schemas.
backend/packages/harness/deerflow/runtime/runs/worker.py: invoke goal coordinator after successful run finalization and before bridge.publish_end() or immediately after checkpoint-safe finalization.
backend/app/gateway/routers/goals.py: explicit Web/API goal operations.
backend/app/gateway/services.py: command-aware run creation or context metadata for /goal submissions.
frontend/src/components/workspace/input-box.tsx: command autocomplete and submit routing.
frontend/src/core/threads/types.ts: goal?: GoalState.
frontend/src/components/workspace/goal-progress-row.tsx: visual status and clear action.
Observability
Add run events for:
goal.set
goal.evaluate.started
goal.evaluate.completed
goal.continuation.scheduled
goal.achieved
goal.cleared
goal.failed
Token attribution should separate main-agent tokens from evaluator tokens, similar to how middleware/title usage is already tracked separately.
Testing plan
Backend unit tests:
- Slash parser reserves
/goal and does not route it to skill activation.
merge_goal preserves existing state on None and replaces on explicit updates.
- Evaluator parses strict JSON and handles malformed output safely.
- Coordinator marks achieved on
ok=true.
- Coordinator schedules continuation on
ok=false.
- Coordinator stops at consecutive block cap.
- Coordinator does not evaluate interrupted/error runs.
- Coordinator does not schedule if thread already has an active run.
- Hidden goal-control messages are excluded from memory/title-visible user message logic.
Backend integration tests:
- Set goal -> agent run -> evaluator fail -> continuation run is created.
- Set goal -> evaluator pass -> goal becomes achieved and no continuation run is created.
/goal clear cancels active goal and no continuation is scheduled.
- Resume/checkpointer restores an active goal.
Frontend tests:
/goal appears in slash autocomplete.
/goal <condition> routes through goal command flow.
- Active goal row renders condition, turn count, token spend, and evaluator reason.
- Clear action updates the UI.
- Existing
/skill-name ... behavior continues to work.
E2E tests:
- Mock backend stream with
values.goal and verify UI updates.
- Mock a fail evaluation followed by continuation status.
- Mock achieved state and verify no active indicator remains.
Rollout plan
Phase 1: Data model and command plumbing
- Add
GoalState to ThreadState.
- Reserve
/goal against slash-skill activation.
- Add shared built-in command parsing.
- Add explicit goal API and frontend state types.
Phase 2: Evaluator and coordinator
- Implement evaluator model call with strict JSON parsing.
- Implement post-run coordinator and continuation scheduling.
- Add loop caps and safety guards.
- Add run events and token attribution.
Phase 3: UI polish and cross-surface parity
- Add
GoalProgressRow in Web.
- Add TUI
/goal status and indicator.
- Add IM/channel behavior or document unsupported surfaces.
- Add docs in README/frontend/backend AGENTS as appropriate.
Phase 4: Optional advanced verification
- Consider command/agent-based deterministic verifiers for projects that want tool-access evaluation.
- Consider goal history beyond the latest achieved/cleared goal.
- Consider scheduled/background goals independent of an open thread, which is out of scope for this RFC.
Open questions
- Should Web goals be strictly thread-scoped, while TUI goals are session-scoped, or should all DeerFlow surfaces share thread-scoped semantics?
- Should the evaluator inspect persisted run events or only serialized visible transcript + state snapshots?
- Should evaluator tokens count against normal thread token budgets, a separate goal-evaluator budget, or both?
- Should
/goal <condition> be available in IM channels, where repeated auto-continuation may surprise users?
- Should active goals survive server restart by default when using SQLite/Postgres checkpointers?
- Is a model-only evaluator enough for v1, or do we need a deterministic command-hook equivalent for CI/test-heavy goals?
Acceptance criteria for the RFC implementation
- Users can set, inspect, and clear one active
/goal per thread/session.
/goal cannot conflict with slash-skill activation.
- A successful agent run with an active goal triggers evaluator execution.
- Evaluator
ok=false schedules a bounded continuation run with visible rationale.
- Evaluator
ok=true marks the goal achieved and stops continuation.
- Loop caps prevent indefinite continuation.
- Frontend displays active/achieved/cleared goal state.
- Tests cover parser, state reducer, evaluator parsing, coordinator decisions, and frontend rendering.
Summary
Add a first-class
/goalcommand to DeerFlow, modeled after Claude Code's goal feature: a user sets a verifiable completion condition, DeerFlow runs the lead agent, and after each completed turn a separate lightweight evaluator decides whether the condition is satisfied. If not, DeerFlow automatically starts the next continuation turn with the evaluator reason as guidance. If yes, the goal is cleared/recorded as achieved.This should be implemented as a thread/session-level completion contract, not as a skill and not as a stronger prompt inside the main agent.
External reference
Claude Code's documented behavior is the reference design:
/goalsets a completion condition and keeps the current session running across turns until that condition is met./goalshows status;/goal clearand aliases cancel it.References:
Motivation
DeerFlow already supports long-running agent work, plan mode, todos, subagents, sandboxed execution, thread persistence, and streaming. However, users still need to manually decide when to send the next prompt for long-horizon work. A Claude Code-style
/goalgives DeerFlow a higher-level workflow primitive:The important distinction is that completion is judged by a separate evaluator at run finalization time, not by the same agent that is doing the work.
Current DeerFlow fit
Useful existing pieces:
ThreadStatealready persists structured state such astodos,artifacts, andtitlethrough the checkpointer.TodoMiddlewarealready gives multi-step progress visibility whenis_plan_modeis true.SkillActivationMiddlewarealready owns/skill-name ...semantics, so/goalmust be a reserved built-in command, not a skill.backend/packages/harness/deerflow/tui/command_registry.py.frontend/src/components/workspace/input-box.tsxandfrontend/src/core/threads/hooks.ts.app.gateway.services.create_run_record_and_task()anddeerflow.runtime.runs.worker.run_agent().run_agent()has a finalization point after success/error/interruption, token usage persistence, title sync, thread-meta status update, andbridge.publish_end().RunManager.create_or_reject()already serializes active runs per thread and supports reject/interrupt/rollback strategies.Proposed behavior
Command semantics
Add
/goalas a built-in command across Web, TUI, and eventually IM/headless clients.Supported forms:
/goal <condition>: set or replace the active goal, then immediately start a turn using the condition as the directive./goal: show active goal status, or the most recently achieved/cleared goal for the current thread/session./goal clear: clear the active goal without marking it achieved.stop,off,reset,none,cancel.Initial non-goals:
/goala DeerFlow skill.Thread state
Extend
ThreadStatewith a reducer-backedgoalchannel. Suggested shape:Reducer semantics should mirror
merge_todos:Nonepreserves existing goal state; an explicit goal update replaces it.Questions for implementation:
/goalstatus, or move to run/thread metadata after completion?Recommended v1 answer: persist the active goal in
ThreadStateso Web, TUI, and Gateway agree. Keep the latest achieved/cleared entry in the same state for status display. Revisit a historical goal log later.Slash command ownership
Add
goaltoRESERVED_SLASH_SKILL_NAMESindeerflow.skills.slashso/goalcannot be interpreted as/goalskill activation.Create a shared command parser rather than duplicating Web/TUI behavior:
deerflow.commands.registry.goal,help,new,resume, etc./goalas a built-in command alongside enabled skills.Goal run flow
The core loop should live outside the agent graph, near run finalization:
/goal <condition>.ThreadState.goalas active.run_agent()reaches finalization with statussuccess.goal.status=achieved, store reason, publish a goal event, and leave thread idle.goal.last_reason, increment counters, and enqueue one continuation run with a hidden/system control prompt containing the reason.The continuation run should use
multitask_strategy="reject"and should only be scheduled after the completed run fully exits, so it does not race the previous run's checkpoint writes.Evaluator
Introduce
deerflow.runtime.goals.evaluatoror similar.Inputs:
Output schema:
{ "ok": true, "reason": "The transcript shows `pytest backend/tests/test_goal.py` exited 0 and the goal condition only required that check." }or
{ "ok": false, "reason": "The implementation changed backend files, but no test result has been surfaced yet.", "guidance": "Run the relevant backend tests and surface the exact command and exit status." }The evaluator should use a configured small/fast model, similar in spirit to Claude Code defaulting goal evaluation to the configured small fast model. DeerFlow can follow existing patterns from title generation and suggestions:
The evaluator should not call tools in v1. This keeps it cheap and avoids giving an automated stop-condition checker its own side effects. A later v2 could add an agent-based verifier, but only with explicit config and limits.
Continuation prompt
Continuation prompts should be hidden from normal chat UI but persisted enough for reproducibility. Example content:
Display rules:
Safety and loop limits
Borrow the same failure posture as Claude Code Stop hooks:
Frontend
Add a
GoalProgressRoworGoalPanelnear the composer, parallel to the existing To-do panel.It should show:
Web command UX:
/goalas a built-in slash command./goal <condition>should not be sent as a literal user-visible task if the backend command API can set the state directly; alternatively, v1 can submit the condition as the user directive but mark the slash command metadata for display cleanup./goalstatus should open/show the goal panel or append a compact status message./goal clearshould call a goal API and update thread state without starting a normal agent turn.APIs
Possible Gateway endpoints:
GET /api/threads/{thread_id}/goalPUT /api/threads/{thread_id}/goalwith{ condition }DELETE /api/threads/{thread_id}/goalPOST /api/threads/{thread_id}/goal/evaluatefor tests/debug only.However, the LangGraph-compatible path still needs to surface goal updates through thread state snapshots so the existing
useStreamfrontend state model works.Backend integration points
Recommended module placement:
backend/packages/harness/deerflow/agents/thread_state.py:GoalState,merge_goal,goalfield.backend/packages/harness/deerflow/commands/: shared slash command registry and parser.backend/packages/harness/deerflow/runtime/goals/: goal evaluator, coordinator, prompt builder, schemas.backend/packages/harness/deerflow/runtime/runs/worker.py: invoke goal coordinator after successful run finalization and beforebridge.publish_end()or immediately after checkpoint-safe finalization.backend/app/gateway/routers/goals.py: explicit Web/API goal operations.backend/app/gateway/services.py: command-aware run creation or context metadata for/goalsubmissions.frontend/src/components/workspace/input-box.tsx: command autocomplete and submit routing.frontend/src/core/threads/types.ts:goal?: GoalState.frontend/src/components/workspace/goal-progress-row.tsx: visual status and clear action.Observability
Add run events for:
goal.setgoal.evaluate.startedgoal.evaluate.completedgoal.continuation.scheduledgoal.achievedgoal.clearedgoal.failedToken attribution should separate main-agent tokens from evaluator tokens, similar to how middleware/title usage is already tracked separately.
Testing plan
Backend unit tests:
/goaland does not route it to skill activation.merge_goalpreserves existing state onNoneand replaces on explicit updates.ok=true.ok=false.Backend integration tests:
/goal clearcancels active goal and no continuation is scheduled.Frontend tests:
/goalappears in slash autocomplete./goal <condition>routes through goal command flow./skill-name ...behavior continues to work.E2E tests:
values.goaland verify UI updates.Rollout plan
Phase 1: Data model and command plumbing
GoalStatetoThreadState./goalagainst slash-skill activation.Phase 2: Evaluator and coordinator
Phase 3: UI polish and cross-surface parity
GoalProgressRowin Web./goalstatus and indicator.Phase 4: Optional advanced verification
Open questions
/goal <condition>be available in IM channels, where repeated auto-continuation may surprise users?Acceptance criteria for the RFC implementation
/goalper thread/session./goalcannot conflict with slash-skill activation.ok=falseschedules a bounded continuation run with visible rationale.ok=truemarks the goal achieved and stops continuation.