Skip to content

feat: 添加 /goal 命令,支持长时间运行任务的目标管理#1222

Open
Fearless743 wants to merge 4 commits into
claude-code-best:mainfrom
Fearless743:feat/goal-command
Open

feat: 添加 /goal 命令,支持长时间运行任务的目标管理#1222
Fearless743 wants to merge 4 commits into
claude-code-best:mainfrom
Fearless743:feat/goal-command

Conversation

@Fearless743
Copy link
Copy Markdown

@Fearless743 Fearless743 commented May 12, 2026

从 Codex 项目移植 /goal 命令到 Claude Code,实现:

  • Goal 状态管理模块(active/paused/budget_limited/complete)
  • /goal 斜杠命令(set/clear/pause/resume/complete)
  • Goal 模型工具(get/set/complete)
  • Continuation prompt 自动注入系统提示
  • Token 用量自动追踪

View in Codesmith
Need help on this PR? Tag @codesmith with what you need.

  • Let Codesmith autofix CI failures and bot reviews

Summary by CodeRabbit

  • New Features
    • Built-in Goal tool for managing long-running objectives (get/set/complete)
    • Added /goal command to create, pause, resume, replace, and complete goals
    • Per-session goal state with token-usage tracking and budget-aware behavior
    • System prompts updated to include goal state and token accounting; goal completion preserves usage accounting

Review Change Stack

从 Codex 项目移植 /goal 命令到 Claude Code,实现:
- Goal 状态管理模块(active/paused/budget_limited/complete)
- /goal 斜杠命令(set/clear/pause/resume/complete)
- Goal 模型工具(get/set/complete)
- Continuation prompt 自动注入系统提示
- Token 用量自动追踪

Co-Authored-By: mimo-v2.5-pro <XiaomiMiMo@claude-code-best.win>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0fda3ebd-b0fb-4f47-8e11-364cc3e03109

📥 Commits

Reviewing files that changed from the base of the PR and between 547c959 and 2f30879.

📒 Files selected for processing (2)
  • packages/builtin-tools/src/tools/GoalTool/GoalTool.ts
  • src/services/goal/goalState.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/builtin-tools/src/tools/GoalTool/GoalTool.ts
  • src/services/goal/goalState.ts

📝 Walkthrough

Walkthrough

Adds session-scoped goal state, a GoalTool (get/set/complete), a local /goal command with subcommands, and integrations for token accounting and a dynamic system-prompt section reflecting goal state between turns.

Changes

Goal Management Feature

Layer / File(s) Summary
Goal state management foundation
src/services/goal/goalState.ts
GoalStatus and GoalState types define lifecycle and per-session storage in a Map; exported functions provide CRUD (setGoal, getGoal, clearGoal, clearAllGoals), transitions (pauseGoal, resumeGoal, completeGoal), token usage tracking with budget enforcement, getGoalContinuationPrompt, and formatGoalStatus.
GoalTool definition and packaging
packages/builtin-tools/src/tools/GoalTool/GoalTool.ts, packages/builtin-tools/src/tools/GoalTool/prompt.ts, packages/builtin-tools/src/index.ts
Adds Zod input/output schemas and a buildTool-based GoalTool (actions: get/set/complete) with permission gating, call handler invoking session goal functions, human-readable renderers, Anthropic tool-result mapping, a prompt generator, and a barrel re-export.
Goal command with subcommands
src/commands/goal/index.ts, src/commands/goal/goal.ts, src/commands.ts
Introduces a local /goal command supporting non-interactive use, dispatches control subcommands (clear, pause, resume, complete), sets/replaces goals, returns formatted status text, and is registered in the command list.
Token tracking and prompt injection
src/tools.ts, src/query.ts, src/constants/prompts.ts
Query processing computes assistant token totals and calls updateGoalTokens; getGoalContinuationPrompt() is injected as an uncached dynamic system-prompt section (goal_continuation); GoalTool is added to the base tool pool.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant GoalTool
  participant GoalState
  User->>GoalTool: call(action: "set", objective, tokenBudget?, sessionId?)
  GoalTool->>GoalState: setGoal(objective, tokenBudget, sessionId?)
  GoalState-->>GoalTool: GoalState
  GoalTool-->>User: Output(success)
  User->>GoalTool: call(action: "get", sessionId?)
  GoalTool->>GoalState: getGoal(sessionId?)
  GoalState-->>GoalTool: GoalState (elapsed,tokens)
  GoalTool-->>User: Output(get payload)
  User->>GoalTool: call(action: "complete", message?, sessionId?)
  GoalTool->>GoalState: completeGoal(sessionId?)
  GoalState-->>GoalTool: boolean
  GoalTool-->>User: Output(completed)
Loading

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐇 A goal in mind, now tracked with care,
Token budgets set, and states to declare,
Get, set, complete—the long task awaits,
With pauses between and completion's gate,
New prompts and tools make progress clear.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is in Chinese and describes adding a /goal command for long-running task goal management, which directly matches the PR's main objective of implementing goal state management and slash command functionality.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/commands/goal/goal.ts (1)

54-62: ⚡ Quick win

Include the previous goal objective in the replacement message.

When replacing an existing active goal, the user only sees "Goal replaced" without being reminded what they just overwrote. This could be surprising if they forgot they had an active goal.

💬 Suggested enhancement
 if (existing && existing.status === 'active') {
   // Replace existing active goal
+  const previousObjective = existing.objective
   setGoal(trimmed)
   return {
     type: 'text',
-    value: `Goal replaced.\n\n${formatGoalStatus()}`,
+    value: `Goal replaced (was: "${previousObjective}").\n\n${formatGoalStatus()}`,
   }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/commands/goal/goal.ts` around lines 54 - 62, When replacing an existing
active goal in the block that calls getGoal(), include the previous goal's
objective in the replacement response: read the existing goal from getGoal(),
save it (e.g., existing.objective), then call setGoal(trimmed) as before and
return a message that includes both the previous objective and the new formatted
status from formatGoalStatus(); update the returned value in that branch so the
user sees what was overwritten along with the new goal status.
src/services/goal/goalState.ts (1)

11-30: 🏗️ Heavy lift

Consider persisting goal state for long-running tasks.

The goal state is purely in-memory and will be lost if the process restarts (crash, upgrade, or user stops/resumes the session). For long-running tasks, this means:

  • Token usage accounting resets to zero
  • Budget enforcement breaks (user could exceed budget after restart)
  • Goal progress tracking is lost

For an MVP this may be acceptable, but if goals are meant to survive across days or session restarts, consider persisting to the session file (similar to how message history is persisted).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/goal/goalState.ts` around lines 11 - 30, The currentGoal in
goalState.ts is only in-memory and should be persisted so goals survive
restarts; update getGoal, setGoal, and clearGoal (and the module-level
currentGoal/GoalState usage) to read/write the goal state to the session
persistence used for message history (load persisted goal on module init, write
the new goal on setGoal, and remove it on clearGoal), ensuring
tokenBudget/tokensUsed/startTime are saved and restored atomically so budget
accounting and status survive process restarts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/services/goal/goalState.ts`:
- Line 11: current module-level currentGoal: GoalState | null is global to the
process and will leak between concurrent daemon/background sessions; replace it
with a session-scoped store (e.g., const goals = new Map<string, GoalState>())
and update the module's public helpers (replace or overload functions that
currently read/write currentGoal) to accept a sessionId parameter or to resolve
sessionId internally, following the pattern in
src/services/api/sessionIngress.ts; specifically: remove the single
"currentGoal" symbol, introduce "goals: Map<sessionId, GoalState>", implement
getGoal(sessionId), setGoal(sessionId, goal), clearGoal(sessionId) and update
any existing functions that reference currentGoal to use these new helpers so
each session has isolated GoalState.

---

Nitpick comments:
In `@src/commands/goal/goal.ts`:
- Around line 54-62: When replacing an existing active goal in the block that
calls getGoal(), include the previous goal's objective in the replacement
response: read the existing goal from getGoal(), save it (e.g.,
existing.objective), then call setGoal(trimmed) as before and return a message
that includes both the previous objective and the new formatted status from
formatGoalStatus(); update the returned value in that branch so the user sees
what was overwritten along with the new goal status.

In `@src/services/goal/goalState.ts`:
- Around line 11-30: The currentGoal in goalState.ts is only in-memory and
should be persisted so goals survive restarts; update getGoal, setGoal, and
clearGoal (and the module-level currentGoal/GoalState usage) to read/write the
goal state to the session persistence used for message history (load persisted
goal on module init, write the new goal on setGoal, and remove it on clearGoal),
ensuring tokenBudget/tokensUsed/startTime are saved and restored atomically so
budget accounting and status survive process restarts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f3dc8d76-d36e-4548-9275-42e428983b6f

📥 Commits

Reviewing files that changed from the base of the PR and between 3d7b32f and b4af442.

📒 Files selected for processing (10)
  • packages/builtin-tools/src/index.ts
  • packages/builtin-tools/src/tools/GoalTool/GoalTool.ts
  • packages/builtin-tools/src/tools/GoalTool/prompt.ts
  • src/commands.ts
  • src/commands/goal/goal.ts
  • src/commands/goal/index.ts
  • src/constants/prompts.ts
  • src/query.ts
  • src/services/goal/goalState.ts
  • src/tools.ts

Comment thread src/services/goal/goalState.ts Outdated
将 currentGoal 单例替换为 Map<string, GoalState>,按 sessionId 隔离,
遵循 sessionIngress.ts 的模式。所有函数支持可选 sessionId 参数。

Co-Authored-By: mimo-v2.5-pro <XiaomiMiMo@claude-code-best.win>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/services/goal/goalState.ts`:
- Around line 39-50: The elapsed time continues to count while a goal is paused
because formatters still compute elapsed from the original startTime; fix by
tracking paused intervals on the Goal object and using an accumulated active
duration. Specifically, add fields like pausedAt: number | null and
accumulatedActiveMs: number to the goal returned by getGoal, update
pauseGoal(sessionId) to set pausedAt = now and leave accumulatedActiveMs
unchanged, and update resumeGoal(sessionId) to add (now - pausedAt) to a
lastPausedDuration or adjust accumulatedActiveMs then clear pausedAt and keep
status = 'active'. Finally, change the elapsed-time calculations in the
status/formatting code (the code that reads startTime to compute "Time spent")
to use accumulatedActiveMs + (if status === 'active' and pausedAt == null ? now
- lastResumedAt : 0) instead of raw now - startTime so paused intervals are
excluded.
- Around line 19-31: The setGoal function currently accepts tokenBudget and
tokensUsed without validation which allows NaN/Infinity/negative values to
corrupt GoalState; before creating and mutating the state in setGoal validate
tokenBudget with Number.isFinite and >= 0 (treat invalid values as null) and
ensure tokensUsed is a finite non-negative number (default/clamp to 0); apply
the same guards anywhere else in this module that writes GoalState.tokensUsed or
tokenBudget (search for assignments to tokensUsed and tokenBudget) so those
mutations also coerce/validate inputs before updating the map.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 129f2bcd-df1e-4a84-8d76-b46a0c48e9a5

📥 Commits

Reviewing files that changed from the base of the PR and between b4af442 and 8783746.

📒 Files selected for processing (1)
  • src/services/goal/goalState.ts

Comment thread src/services/goal/goalState.ts
Comment thread src/services/goal/goalState.ts
Fearless743 and others added 2 commits May 13, 2026 06:48
setGoal 中 tokenBudget 非 finite 或负数时归零;
updateGoalTokens 中 usage 非 finite 或负数时归零。

Co-Authored-By: mimo-v2.5-pro <XiaomiMiMo@claude-code-best.win>
新增 pausedAt/accumulatedActiveMs 字段,pauseGoal 累积已活跃时间,
resumeGoal 重置 startTime,计时统一使用 getActiveElapsedMs()。

Co-Authored-By: mimo-v2.5-pro <XiaomiMiMo@claude-code-best.win>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant