Skip to content

feat: add workboard_get_team_objectives_tool for date-range-scoped OKR snapshots#24

Open
ghelleks wants to merge 2 commits into
crunchtools:mainfrom
ghelleks:feat/team-objectives-date-range
Open

feat: add workboard_get_team_objectives_tool for date-range-scoped OKR snapshots#24
ghelleks wants to merge 2 commits into
crunchtools:mainfrom
ghelleks:feat/team-objectives-date-range

Conversation

@ghelleks
Copy link
Copy Markdown
Contributor

Problem

workboard_get_objectives_tool fetches objectives by owner user ID and silently
filters out any objective whose goal_target_date is in the past. This means
Q1 objectives disappear after March 31, making the tool unreliable for weekly
OKR snapshots or any cross-quarter review.

The WorkBoard web UI avoids this by using a team-scoped, date-range-filtered
endpoint instead:

GET /goal/goalSummary?team_people=1&team_s=0&userTeamid=...&startDate=...&endDate=...&exDate=1

Solution

Adds workboard_get_team_objectives_tool, a new read-only MCP tool that wraps
this endpoint. The date window is owned entirely by the API — no client-side
expiry filtering is applied — so objectives from any quarter are returned
correctly.

New public surface

File Change
errors.py InvalidTeamIdError
models.py validate_team_id, validate_mm_dd_yyyy (MM/DD/YYYY format validator)
tools/objectives.py get_team_objectives — calls GET /goal/goalSummary with fixed params
tools/__init__.py exports get_team_objectives
server.py workboard_get_team_objectives_tool MCP wrapper + instructions note

Tool signature

workboard_get_team_objectives_tool(
    team_id: int,        # from workboard_get_teams_tool
    start_date: str,     # MM/DD/YYYY, e.g. "04/01/2026"
    end_date: str,       # MM/DD/YYYY, e.g. "06/30/2026"
    get_nested_teams: bool = True,
) -> dict

Returns {"objectives": [...]} where each item includes name, owner,
status_color, progress, and key_results (name, progress, last_updated).

Fixed query params

Param Value Notes
team_people 1 match UI
team_s 0 match UI
userTeamType 2 match UI
status 1 active
performance 4,3,2,1,0 all statuses
exDate 1 include expired

Tests

  • Mock-based happy-path test asserting correct API path, query params
    (userTeamid, startDate, endDate, performance, exDate), and
    normalized output fields.
  • get_nested_teams=False passes "false" string to API.
  • Invalid team_id raises InvalidTeamIdError.
  • Wrong date format (ISO instead of MM/DD/YYYY) raises ValidationError.
  • Unit tests for validate_team_id and validate_mm_dd_yyyy.
  • test_tool_count bumped from 22 → 23.

All 112 existing tests continue to pass.

…R snapshots

The existing workboard_get_objectives_tool fetches objectives by owner user ID
and silently excludes those with a past target date, making it useless for
quarterly OKR snapshots after quarter-end (e.g. Q1 objectives vanish after
March 31).

This adds workboard_get_team_objectives_tool, which calls the goalSummary
endpoint used by the WorkBoard web UI. The date range is passed directly to
the API so past-quarter objectives are returned correctly.

New public surface:
- errors.py: InvalidTeamIdError
- models.py: validate_team_id, validate_mm_dd_yyyy (MM/DD/YYYY validator)
- tools/objectives.py: get_team_objectives (GET /goal/goalSummary)
- tools/__init__.py: export get_team_objectives
- server.py: workboard_get_team_objectives_tool MCP wrapper + instructions update

Tests: mock-based tests for get_team_objectives (happy path, get_nested_teams=False,
invalid team_id, invalid date format); validate_team_id and validate_mm_dd_yyyy
unit tests; test_tool_count bumped from 22 → 23.
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new tool, workboard_get_team_objectives_tool, which allows fetching team-scoped objectives within a specific date range using the WorkBoard goalSummary API. The changes include new error classes, validation logic for team IDs and date formats (MM/DD/YYYY), and updated unit tests. Review feedback highlights the need to align parameter names in the tool's documentation with the implementation, ensure docstring field names match the actual output, and include an enrichment step for key result target dates to maintain consistency with other objective-related tools.

"effort, due date, or owner.\n\n"
"TEAM OKR SNAPSHOTS: For quarterly OKR reviews or weekly snapshots that include "
"past-quarter objectives, use workboard_get_team_objectives_tool with a team_id "
"and explicit MM/DD/YYYY date bounds (e.g. startDate='01/01/2026', endDate='03/31/2026'). "
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The parameter names in the example instructions (startDate, endDate) do not match the actual tool parameter names (start_date, end_date). This will cause the LLM to provide incorrect arguments when calling the tool.

Suggested change
"and explicit MM/DD/YYYY date bounds (e.g. startDate='01/01/2026', endDate='03/31/2026'). "
"and explicit MM/DD/YYYY date bounds (e.g. start_date='01/01/2026', end_date='03/31/2026'). "


Returns:
List of objectives with name, owner, status_color, progress, and
nested key_results (name, progress, last_updated, target).
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The docstring lists target as a field in key_results, but the underlying _format_metric function returns this field as target_date. This discrepancy can lead to confusion for users or AI models consuming the tool output.

Suggested change
nested key_results (name, progress, last_updated, target).
nested key_results (name, progress, last_updated, target_date).

Comment on lines +668 to +673
response = await client.get("/goal/goalSummary", params=params)

body = response.get("data", {})
goals = _extract_goals_from_goal_response(body)

return {"objectives": [_format_goal(g) for g in goals]}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This tool is missing the enrichment step for key result target dates. Other objective-related tools in this module (like get_objectives) fetch a target date map from the /metric endpoint because the goal summary response typically leaves these fields empty. Without this, the target_date field in the returned key results will likely be empty.

Suggested change
response = await client.get("/goal/goalSummary", params=params)
body = response.get("data", {})
goals = _extract_goals_from_goal_response(body)
return {"objectives": [_format_goal(g) for g in goals]}
response, metric_target_dates = await asyncio.gather(
client.get("/goal/goalSummary", params=params),
_fetch_target_date_map(client),
)
body = response.get("data", {})
goals = _extract_goals_from_goal_response(body)
return {"objectives": [_format_goal(g, metric_target_dates) for g in goals]}

@ghelleks
Copy link
Copy Markdown
Contributor Author

Tracking issue for this work (including WorkBoard API blocker): #25

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