derive_subgoal
Propose a sub-goal under an existing parent goal to break down strategic objectives. Use draft status for autonomous creation and human review before activation.
Instructions
Propose a sub-goal under an existing parent goal. parent_goal_id is mandatory — agents cannot create top-level goals (strategic direction is human-set). Defaults to status='active' for human-directed creation; pass status='draft' for autonomous loops so a human can review before promotion. Drafts surface in the dashboard pending queue.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| parent_goal_id | Yes | Required. The parent goal this sub-goal contributes to. | |
| title | Yes | ||
| description | No | Optional extended description, appended after rationale. | |
| rationale | Yes | Why this sub-goal is needed to achieve the parent. Becomes the description; surfaces in human review. | |
| type | No | outcome | |
| status | No | Default 'active' for human-directed creation. Pass 'draft' when acting autonomously without explicit user direction. | active |
| success_criteria | No | Concrete, observable conditions that mark this sub-goal achieved. | |
| priority | No |
Implementation Reference
- src/tools/bdi/desires.js:209-255 (handler)The deriveSubgoalHandler async function that executes the derive_subgoal tool logic. It validates the parent goal exists, composes description from rationale, constructs a payload, creates the sub-goal via the API client, and returns a formatted response.
async function deriveSubgoalHandler(args, apiClient) { const { parent_goal_id, title, description, rationale, type = 'outcome', status = 'active', success_criteria, priority } = args; // Verify parent exists and inherit organization scope. let parent; try { parent = await apiClient.goals.get(parent_goal_id); } catch (err) { return errorResponse('not_found', `Parent goal ${parent_goal_id} not found or not accessible: ${err.message}`); } // Compose description: rationale is primary; optional description appended. const composedDescription = description ? `${rationale}\n\n${description}` : rationale; const payload = { title, description: composedDescription, type, status, parentGoalId: parent_goal_id, organizationId: parent.organization_id || parent.organizationId || undefined, }; if (success_criteria) payload.successCriteria = { criteria: success_criteria }; if (typeof priority === 'number') payload.priority = priority; let goal; try { goal = await apiClient.goals.create(payload); } catch (err) { const upstream = err.response?.data?.error || err.message; return errorResponse('create_failed', `Failed to create sub-goal: ${upstream}`); } return formatResponse({ as_of: asOf(), goal_id: goal.id, parent_goal_id, title: goal.title, status: goal.status, is_draft: goal.status === 'draft', next_step: goal.status === 'draft' ? "Sub-goal created as draft. It will surface in the dashboard pending queue for human review. Promote via update_goal({status: 'active'}) once approved." : "Sub-goal active. Link plans to it via update_goal({add_linked_plans: [...]}).", }); } - src/tools/bdi/desires.js:166-207 (schema)The deriveSubgoalDefinition object containing the tool name, description, and inputSchema (which defines the JSON schema for all parameters: parent_goal_id, title, description, rationale, type, status, success_criteria, priority).
const deriveSubgoalDefinition = { name: 'derive_subgoal', description: "Propose a sub-goal under an existing parent goal. parent_goal_id is " + "mandatory — agents cannot create top-level goals (strategic direction is " + "human-set). Defaults to status='active' for human-directed creation; pass " + "status='draft' for autonomous loops so a human can review before promotion. " + "Drafts surface in the dashboard pending queue.", inputSchema: { type: 'object', properties: { parent_goal_id: { type: 'string', description: "Required. The parent goal this sub-goal contributes to.", }, title: { type: 'string' }, description: { type: 'string', description: "Optional extended description, appended after rationale." }, rationale: { type: 'string', description: "Why this sub-goal is needed to achieve the parent. Becomes the description; surfaces in human review.", }, type: { type: 'string', enum: VALID_GOAL_TYPES, default: 'outcome', }, status: { type: 'string', enum: VALID_STATUSES, default: 'active', description: "Default 'active' for human-directed creation. Pass 'draft' when acting autonomously without explicit user direction.", }, success_criteria: { type: 'array', items: { type: 'string' }, description: "Concrete, observable conditions that mark this sub-goal achieved.", }, priority: { type: 'integer', default: 0 }, }, required: ['parent_goal_id', 'title', 'rationale'], }, }; - src/tools/bdi/desires.js:257-264 (registration)Module exports registering deriveSubgoalDefinition in the definitions array and deriveSubgoalHandler as derive_subgoal in the handlers map.
module.exports = { definitions: [listGoalsDefinition, updateGoalDefinition, deriveSubgoalDefinition], handlers: { list_goals: listGoalsHandler, update_goal: updateGoalHandler, derive_subgoal: deriveSubgoalHandler, }, }; - src/tools/bdi/index.js:16-28 (registration)BDI index aggregating all definitions and handlers (including derive_subgoal from desires) into merged arrays/maps, and exposing them via bdiToolDefinitions and bdiToolHandler.
const definitions = [ ...beliefs.definitions, ...desires.definitions, ...intentions.definitions, ...utility.definitions, ]; const handlers = { ...beliefs.handlers, ...desires.handlers, ...intentions.handlers, ...utility.handlers, }; - src/tools.js:30-48 (registration)Top-level tools.js wiring: bdiToolHandler dispatches CallToolRequestSchema requests by name (e.g., 'derive_subgoal') to the correct handler.
server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; if (process.env.NODE_ENV === 'development') { console.error(`Calling tool: ${name}`); } if (!bdiToolNames.has(name)) { return { isError: true, content: [{ type: 'text', text: `Unknown tool: ${name}. v0.9.0 ships 15 BDI tools. Run get_started to see them, or check ../docs/MIGRATION_v0.9.md for the legacy → BDI mapping.`, }], }; } try { return await bdiToolHandler(name, args, apiClient);