tools

package
v0.4.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 19, 2026 License: MIT Imports: 31 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ValidateRegistry added in v0.4.0

func ValidateRegistry(reg []mcp.ToolDescriptor) error

ValidateRegistry checks the assembled tool registry for contract violations: duplicate tool names and ordering errors (raw API fallback tools must come last). It returns a descriptive error on the first violation, or nil when the registry is well-formed.

Types

type ApprovalAuditTrail

type ApprovalAuditTrail struct {
	State         string         `json:"state,omitempty"`
	UpdatedBy     string         `json:"updated_by,omitempty"`
	UpdatedByName string         `json:"updated_by_name,omitempty"`
	UpdatedAt     string         `json:"updated_at,omitempty"`
	Note          string         `json:"note,omitempty"`
	Creator       map[string]any `json:"creator,omitempty"`
	Source        string         `json:"source,omitempty"`
	Raw           map[string]any `json:"raw,omitempty"`
}

ApprovalAuditTrail captures the latest approval-state transition: the state, who changed it and when, and any note.

type ApprovalDurationTotals

type ApprovalDurationTotals struct {
	Approved *EntryDurationView `json:"approved,omitempty"`
	Pending  *EntryDurationView `json:"pending,omitempty"`
	Tracked  *EntryDurationView `json:"tracked,omitempty"`
	Billable *EntryDurationView `json:"billable,omitempty"`
	Break    *EntryDurationView `json:"break,omitempty"`
}

ApprovalDurationTotals breaks down an approval request's durations by category (approved, pending, tracked, billable, break).

type ApprovalExpenseSummary

type ApprovalExpenseSummary struct {
	Count         int        `json:"count"`
	BillableCount int        `json:"billable_count,omitempty"`
	Amount        *MoneyView `json:"amount,omitempty"`
	Source        string     `json:"source"`
	Reason        string     `json:"reason,omitempty"`
}

ApprovalExpenseSummary aggregates the expenses within an approval request: total and billable counts and the total amount.

type ApprovalMoneyTotals

type ApprovalMoneyTotals struct {
	Earned   *MoneyView `json:"earned,omitempty"`
	Cost     *MoneyView `json:"cost,omitempty"`
	Expenses *MoneyView `json:"expenses,omitempty"`
	Profit   *MoneyView `json:"profit,omitempty"`
	Source   string     `json:"source"`
	Reason   string     `json:"reason,omitempty"`
}

ApprovalMoneyTotals breaks down an approval request's money figures (earned, cost, expenses, profit) with source/reason provenance.

type ApprovalView

type ApprovalView struct {
	ID               string                          `json:"id,omitempty"`
	Request          map[string]any                  `json:"request,omitempty"`
	Owner            map[string]any                  `json:"owner,omitempty"`
	Creator          map[string]any                  `json:"creator,omitempty"`
	Status           map[string]any                  `json:"status,omitempty"`
	AuditTrail       *ApprovalAuditTrail             `json:"audit_trail,omitempty"`
	DateRange        any                             `json:"date_range,omitempty"`
	Totals           map[string]any                  `json:"totals,omitempty"`
	DurationTotals   ApprovalDurationTotals          `json:"duration_totals"`
	MoneyTotals      ApprovalMoneyTotals             `json:"money_totals"`
	Financials       EntryFinancials                 `json:"financials"`
	EntrySummary     ReportEntrySummary              `json:"entry_summary"`
	ExpenseSummary   ApprovalExpenseSummary          `json:"expense_summary"`
	ClientSummary    []ReportClientSummary           `json:"client_summary,omitempty"`
	Rollups          map[string][]ReportEntityRollup `json:"rollups,omitempty"`
	Entries          []ReportEntryView               `json:"entries,omitempty"`
	Expenses         []map[string]any                `json:"expenses,omitempty"`
	Actions          []string                        `json:"actions,omitempty"`
	SuggestedActions []ToolSuggestion                `json:"suggestedActions,omitempty"`
	Raw              map[string]any                  `json:"raw,omitempty"`
}

ApprovalView is the fully shaped approval-request output: the request/owner/ status metadata, audit trail, duration and money totals, entry/expense summaries, per-client and per-entity rollups, and the underlying entries.

type AssignmentDurationView

type AssignmentDurationView struct {
	Seconds int64   `json:"seconds"`
	Hours   float64 `json:"hours"`
	Display string  `json:"display,omitempty"`
}

AssignmentDurationView is the normalized duration block (seconds, hours, display) used throughout scheduling-assignment report rows and totals.

type AssignmentReportData

type AssignmentReportData struct {
	Range  FinancialRangeView     `json:"range"`
	Groups []string               `json:"groups"`
	Rows   []AssignmentReportRow  `json:"rows"`
	Totals AssignmentReportTotals `json:"totals"`
	Raw    map[string]any         `json:"raw,omitempty"`
}

AssignmentReportData is the shaped result of a scheduling-assignment report: the date range, the grouping dimensions, the per-group rows, and the totals.

type AssignmentReportMoney

type AssignmentReportMoney struct {
	Earned *MoneyView `json:"earned,omitempty"`
	Cost   *MoneyView `json:"cost,omitempty"`
	Profit *MoneyView `json:"profit,omitempty"`
	Source string     `json:"source"`
	Reason string     `json:"reason,omitempty"`
}

AssignmentReportMoney holds the earned/cost/profit money figures for a scheduling-assignment report scope, with source/reason provenance.

type AssignmentReportRow

type AssignmentReportRow struct {
	Title            string                 `json:"title"`
	GroupKey         map[string]string      `json:"group_key"`
	Entities         map[string]any         `json:"entities,omitempty"`
	Scheduled        AssignmentDurationView `json:"scheduled"`
	Available        AssignmentDurationView `json:"available"`
	AmountScheduled  *MoneyView             `json:"amount_scheduled,omitempty"`
	CostScheduled    *MoneyView             `json:"cost_scheduled,omitempty"`
	ExpectedProfit   *MoneyView             `json:"expected_profit,omitempty"`
	Tracked          AssignmentDurationView `json:"tracked"`
	AmountTracked    *MoneyView             `json:"amount_tracked,omitempty"`
	CostTracked      *MoneyView             `json:"cost_tracked,omitempty"`
	Difference       AssignmentDurationView `json:"difference"`
	AmountDifference *MoneyView             `json:"amount_difference,omitempty"`
	CostDifference   *MoneyView             `json:"cost_difference,omitempty"`
	RealizedProfit   *MoneyView             `json:"realized_profit,omitempty"`
	Status           string                 `json:"status,omitempty"`
	Financials       AssignmentReportMoney  `json:"financials"`
	Source           string                 `json:"source"`
	Warnings         []string               `json:"warnings,omitempty"`
	Raw              map[string]any         `json:"raw,omitempty"`
}

AssignmentReportRow is one grouped row of a scheduling-assignment report: scheduled vs available vs tracked durations and their money figures, plus the computed difference and realized/expected profit.

type AssignmentReportTotals

type AssignmentReportTotals struct {
	Scheduled        AssignmentDurationView `json:"scheduled"`
	Available        AssignmentDurationView `json:"available"`
	Tracked          AssignmentDurationView `json:"tracked"`
	Difference       AssignmentDurationView `json:"difference"`
	AmountScheduled  *MoneyView             `json:"amount_scheduled,omitempty"`
	CostScheduled    *MoneyView             `json:"cost_scheduled,omitempty"`
	ExpectedProfit   *MoneyView             `json:"expected_profit,omitempty"`
	AmountTracked    *MoneyView             `json:"amount_tracked,omitempty"`
	CostTracked      *MoneyView             `json:"cost_tracked,omitempty"`
	AmountDifference *MoneyView             `json:"amount_difference,omitempty"`
	CostDifference   *MoneyView             `json:"cost_difference,omitempty"`
	RealizedProfit   *MoneyView             `json:"realized_profit,omitempty"`
}

AssignmentReportTotals aggregates a scheduling-assignment report across all rows: total scheduled/available/tracked/difference durations and their money figures.

type AssignmentView

type AssignmentView map[string]any

AssignmentView is the pass-through scheduling-assignment projection as a generic map.

type ChangeSet

type ChangeSet struct {
	Created []EntityRef `json:"created,omitempty"`
	Updated []EntityRef `json:"updated,omitempty"`
	Deleted []EntityRef `json:"deleted,omitempty"`
	Reused  []EntityRef `json:"reused,omitempty"`
}

ChangeSet records the entities a write touched, grouped by created, updated, deleted, and reused, for the ToolResult.changed block.

type ClientApprovalSummary

type ClientApprovalSummary struct {
	Source                 string                       `json:"source"`
	Reason                 string                       `json:"reason,omitempty"`
	WithApprovalRequest    int                          `json:"with_approval_request,omitempty"`
	WithoutApprovalRequest int                          `json:"without_approval_request,omitempty"`
	RequestIDs             []string                     `json:"request_ids,omitempty"`
	States                 map[string]int               `json:"states,omitempty"`
	DurationsByState       map[string]EntryDurationView `json:"durations_by_state,omitempty"`
}

ClientApprovalSummary aggregates approval coverage for a client's entries (counts with/without an approval request, per-state counts, and durations by state) for the enriched client view.

type ClientContactView

type ClientContactView struct {
	Email    string `json:"email,omitempty"`
	Address  string `json:"address,omitempty"`
	Note     string `json:"note,omitempty"`
	CCEmails any    `json:"ccEmails,omitempty"`
}

ClientContactView is the contact-details projection (email, address, note, cc-emails) embedded in a ClientView.

type ClientCurrencyView

type ClientCurrencyView struct {
	Code string `json:"code,omitempty"`
	ID   string `json:"id,omitempty"`
}

ClientCurrencyView is the currency projection (code + id) embedded in a ClientView.

type ClientInvoiceSummary

type ClientInvoiceSummary struct {
	TotalCount    int            `json:"total_count,omitempty"`
	ReturnedCount int            `json:"returned_count,omitempty"`
	Amount        *MoneyView     `json:"amount,omitempty"`
	Balance       *MoneyView     `json:"balance,omitempty"`
	Paid          *MoneyView     `json:"paid,omitempty"`
	OverdueCount  int            `json:"overdue_count,omitempty"`
	ByStatus      map[string]int `json:"by_status,omitempty"`
	Source        string         `json:"source"`
	Reason        string         `json:"reason,omitempty"`
}

ClientInvoiceSummary aggregates a client's invoices (counts, amounts, balance, paid, overdue, and a by-status breakdown) for the enriched client view.

type ClientProjectSummary

type ClientProjectSummary struct {
	Count         int  `json:"count"`
	ActiveCount   int  `json:"active_count,omitempty"`
	ArchivedCount int  `json:"archived_count,omitempty"`
	BillableCount int  `json:"billable_count,omitempty"`
	TasksCount    int  `json:"tasks_count,omitempty"`
	Truncated     bool `json:"truncated,omitempty"`
}

ClientProjectSummary aggregates a client's projects (counts by active, archived, billable, and tasks) for the enriched client view.

type ClientTimeSummary

type ClientTimeSummary struct {
	TrackedDurationSeconds int64   `json:"tracked_duration_seconds,omitempty"`
	TrackedHours           float64 `json:"tracked_hours,omitempty"`
	TrackedDisplay         string  `json:"tracked_display,omitempty"`
	EntriesCount           int     `json:"entries_count,omitempty"`
	Source                 string  `json:"source"`
	Reason                 string  `json:"reason,omitempty"`
}

ClientTimeSummary aggregates tracked time for a client (duration, entry count, and the source/reason describing how the figures were derived).

type ClientView

type ClientView struct {
	ID           string `json:"id"`
	Name         string `json:"name"`
	Address      string `json:"address,omitempty"`
	Archived     bool   `json:"archived,omitempty"`
	CCEmails     any    `json:"ccEmails,omitempty"`
	CurrencyCode string `json:"currencyCode,omitempty"`
	CurrencyID   string `json:"currencyId,omitempty"`
	Email        string `json:"email,omitempty"`
	Note         string `json:"note,omitempty"`
	WorkspaceID  string `json:"workspaceId,omitempty"`

	Currency        ClientCurrencyView    `json:"currency"`
	Contact         ClientContactView     `json:"contact"`
	ProjectSummary  ClientProjectSummary  `json:"project_summary"`
	Financials      ProjectFinancials     `json:"financials"`
	TimeSummary     ClientTimeSummary     `json:"time_summary"`
	InvoiceSummary  ClientInvoiceSummary  `json:"invoice_summary"`
	ApprovalSummary ClientApprovalSummary `json:"approval_summary"`
	Warnings        []string              `json:"warnings,omitempty"`
}

ClientView is the shaped client output returned by client tools: the core client fields plus optional enriched project/time/invoice/approval summaries.

type CompactExpenseView

type CompactExpenseView struct {
	ID           string     `json:"id"`
	Date         string     `json:"date,omitempty"`
	Amount       *MoneyView `json:"amount,omitempty"`
	CategoryID   string     `json:"categoryId,omitempty"`
	CategoryName string     `json:"categoryName,omitempty"`
	ProjectID    string     `json:"projectId,omitempty"`
	ProjectName  string     `json:"projectName,omitempty"`
	UserID       string     `json:"userId,omitempty"`
	Billable     bool       `json:"billable,omitempty"`
	Locked       bool       `json:"locked,omitempty"`
	Notes        string     `json:"notes,omitempty"`
}

CompactExpenseView is the trimmed expense projection returned by expense tools: id, date, normalized amount, category/project/user, and flags.

type CompactInvoiceView

type CompactInvoiceView struct {
	ID         string     `json:"id"`
	Number     string     `json:"number,omitempty"`
	Status     string     `json:"status,omitempty"`
	ClientID   string     `json:"clientId,omitempty"`
	ClientName string     `json:"clientName,omitempty"`
	IssuedDate string     `json:"issuedDate,omitempty"`
	DueDate    string     `json:"dueDate,omitempty"`
	Currency   string     `json:"currency,omitempty"`
	Amount     *MoneyView `json:"amount,omitempty"`
}

CompactInvoiceView is the trimmed invoice projection: id, number, status, client, dates, and normalized amount.

type CompactProjectView

type CompactProjectView struct {
	ID         string `json:"id"`
	Name       string `json:"name"`
	ClientID   string `json:"clientId,omitempty"`
	ClientName string `json:"clientName,omitempty"`
	Color      string `json:"color,omitempty"`
	Archived   bool   `json:"archived"`
	Billable   bool   `json:"billable,omitempty"`
	Public     bool   `json:"public,omitempty"`
	Duration   string `json:"duration,omitempty"`
}

CompactProjectView is the trimmed project projection used in list responses: id, name, client, color, and the archived/billable/public/duration fields.

type CompactTimeOffPolicyView

type CompactTimeOffPolicyView struct {
	ID             string `json:"id"`
	Name           string `json:"name"`
	Archived       bool   `json:"archived,omitempty"`
	TimeUnit       string `json:"timeUnit,omitempty"`
	UserCount      int    `json:"userCount"`
	UserGroupCount int    `json:"userGroupCount"`
	AssigneeCount  int    `json:"assigneeCount"`
}

CompactTimeOffPolicyView is the trimmed time-off-policy projection: id, name, time unit, and assignee counts.

type CompactUserView

type CompactUserView struct {
	ID               string `json:"id"`
	Name             string `json:"name"`
	Email            string `json:"email"`
	Status           string `json:"status,omitempty"`
	ActiveWorkspace  string `json:"activeWorkspace,omitempty"`
	DefaultWorkspace string `json:"defaultWorkspace,omitempty"`
}

CompactUserView is the per-user shape emitted by clockify_users_list. It omits the heavy memberships, settings, and custom-field payloads that made the full list overflow the transport budget. clockify_users_profile still returns the full UserView for a single user.

type CustomFieldDefinitionView

type CustomFieldDefinitionView struct {
	ID         string `json:"id,omitempty"`
	Name       string `json:"name,omitempty"`
	Type       string `json:"type,omitempty"`
	Status     string `json:"status,omitempty"`
	EntityType string `json:"entity_type,omitempty"`
	Source     string `json:"source,omitempty"`
}

CustomFieldDefinitionView is the shaped projection of a custom-field definition (id, name, type, status, entity type) returned by custom-field tools.

type CustomFieldValueView

type CustomFieldValueView struct {
	ID            string `json:"id,omitempty"`
	CustomFieldID string `json:"custom_field_id,omitempty"`
	Name          string `json:"name,omitempty"`
	Type          string `json:"type,omitempty"`
	Status        string `json:"status,omitempty"`
	EntityType    string `json:"entity_type,omitempty"`
	Value         any    `json:"value,omitempty"`
	Source        string `json:"source"`
}

CustomFieldValueView is the shaped projection of a custom-field value bound to an entity: the definition metadata plus the concrete Value.

type DateRange

type DateRange struct {
	Start string `json:"start"`
	End   string `json:"end"`
}

DateRange is the inclusive [Start, End] window used by every summary / report payload to describe the period the rollup spans.

type DaySummary

type DaySummary struct {
	Date         string  `json:"date"`
	Entries      int     `json:"entries"`
	TotalSeconds int64   `json:"totalSeconds"`
	TotalHours   float64 `json:"totalHours"`
}

DaySummary is the per-day rollup row used by WeeklySummaryData. Date is RFC 3339 YYYY-MM-DD in the configured timezone.

type EffectiveRate

type EffectiveRate struct {
	Hourly      *clockify.Rate `json:"hourly,omitempty"`
	Cost        *clockify.Rate `json:"cost,omitempty"`
	HourlyScope RateScope      `json:"hourly_scope"`
	CostScope   RateScope      `json:"cost_scope"`
}

EffectiveRate is the resolved hourly + cost rate that should be applied to a given (workspace, project, task, entry, user) combination. The Scope fields tell the caller which layer of the hierarchy supplied the rate so the model can explain its answer.

func ResolveEffectiveRate

func ResolveEffectiveRate(
	ws *clockify.Workspace,
	proj *clockify.Project,
	task *clockify.Task,
	entry *clockify.TimeEntry,
	userID string,
) EffectiveRate

ResolveEffectiveRate walks the Clockify rate hierarchy:

entry > task > project-member (matched on userID) > project >
workspace-member (matched on userID) > workspace

Any of the inputs may be nil. The returned EffectiveRate.Scope is RateScopeNone when no layer supplied a rate. Hourly and Cost are resolved independently because a workspace can legitimately set a cost rate without a billable rate (and vice versa).

type EntityRef

type EntityRef struct {
	Type string `json:"type"`
	ID   string `json:"id"`
	Name string `json:"name,omitempty"`
}

EntityRef identifies one affected entity in a ChangeSet by type, id, and optional name.

type EntryApprovalView

type EntryApprovalView struct {
	RequestID string         `json:"request_id,omitempty"`
	State     string         `json:"state,omitempty"`
	Source    string         `json:"source,omitempty"`
	Raw       map[string]any `json:"raw,omitempty"`
}

EntryApprovalView is the approval projection for a report entry: the request ID and state, with the source field and raw payload for provenance.

type EntryAuditView

type EntryAuditView struct {
	Locked             *bool          `json:"locked,omitempty"`
	MissingDescription *bool          `json:"missing_description,omitempty"`
	MissingProject     *bool          `json:"missing_project,omitempty"`
	MissingTask        *bool          `json:"missing_task,omitempty"`
	Source             string         `json:"source,omitempty"`
	Raw                map[string]any `json:"raw,omitempty"`
}

EntryAuditView flags data-quality issues on a report entry: locked status and missing description/project/task, with the source and raw payload.

type EntryDurationView

type EntryDurationView struct {
	Seconds int64   `json:"seconds"`
	Hours   float64 `json:"hours"`
	Display string  `json:"display"`
	Source  string  `json:"source,omitempty"`
}

EntryDurationView is the normalized duration block used by report-derived entry views and summaries.

type EntryEntitiesView

type EntryEntitiesView struct {
	User    *EntryEntityRef  `json:"user,omitempty"`
	Client  *EntryEntityRef  `json:"client,omitempty"`
	Project *EntryEntityRef  `json:"project,omitempty"`
	Task    *EntryEntityRef  `json:"task,omitempty"`
	Tags    []EntryEntityRef `json:"tags,omitempty"`
}

EntryEntitiesView groups the entity references (user, client, project, task, tags) resolved from a report entry row.

type EntryEntityRef

type EntryEntityRef struct {
	ID    string         `json:"id,omitempty"`
	Name  string         `json:"name,omitempty"`
	Email string         `json:"email,omitempty"`
	Color string         `json:"color,omitempty"`
	Raw   map[string]any `json:"raw,omitempty"`
}

EntryEntityRef keeps entity IDs and names close to the entry that produced them without forcing callers to understand Clockify's varying row shapes.

type EntryFinancials

type EntryFinancials struct {
	Earned *MoneyView     `json:"earned,omitempty"`
	Cost   *MoneyView     `json:"cost,omitempty"`
	Profit *MoneyView     `json:"profit,omitempty"`
	Source string         `json:"source"`
	Reason string         `json:"reason,omitempty"`
	Rate   *EntryRateView `json:"rate,omitempty"`
}

EntryFinancials holds the earned/cost/profit money figures for a single report entry, along with the source/reason and the effective rate that produced them.

type EntryInvoicingView

type EntryInvoicingView struct {
	Invoiced      *bool          `json:"invoiced,omitempty"`
	State         string         `json:"state,omitempty"`
	InvoiceID     string         `json:"invoice_id,omitempty"`
	InvoiceNumber string         `json:"invoice_number,omitempty"`
	Source        string         `json:"source,omitempty"`
	Raw           map[string]any `json:"raw,omitempty"`
}

EntryInvoicingView is the invoicing projection for a report entry: whether it is invoiced, its state, and the linked invoice id/number.

type EntryRateView

type EntryRateView struct {
	EntryHourly      *clockify.Rate `json:"entry_hourly,omitempty"`
	EntryCost        *clockify.Rate `json:"entry_cost,omitempty"`
	EffectiveHourly  *clockify.Rate `json:"effective_hourly,omitempty"`
	EffectiveCost    *clockify.Rate `json:"effective_cost,omitempty"`
	HourlyScope      RateScope      `json:"hourly_scope"`
	CostScope        RateScope      `json:"cost_scope"`
	DurationSeconds  int64          `json:"duration_seconds"`
	BillableEarnings MoneyView      `json:"billable_earnings"`
	Cost             MoneyView      `json:"cost"`
}

EntryRateView is the LLM-facing block we attach to every time-entry row across tool outputs. It bundles the raw entry-level rates (so the caller can see what Clockify itself stored) with the resolved effective rate and the derived per-entry money.

func BuildEntryRateView

func BuildEntryRateView(
	ws *clockify.Workspace,
	proj *clockify.Project,
	task *clockify.Task,
	entry *clockify.TimeEntry,
) EntryRateView

BuildEntryRateView is the canonical adapter from a (workspace, project, task, entry, user) tuple to the EntryRateView envelope. Callers pass whatever context they have; nils are tolerated.

type EntryView

type EntryView struct {
	ID                string                 `json:"id"`
	Description       string                 `json:"description"`
	ProjectID         string                 `json:"projectId"`
	ProjectName       string                 `json:"projectName,omitempty"`
	TaskID            string                 `json:"taskId,omitempty"`
	TagIDs            []string               `json:"tagIds,omitempty"`
	Billable          bool                   `json:"billable"`
	BillableState     string                 `json:"billable_state"`
	BillablePresent   bool                   `json:"billable_present"`
	CostRate          *clockify.Rate         `json:"costRate,omitempty"`
	CustomFieldValues any                    `json:"customFieldValues,omitempty"`
	CustomFields      []CustomFieldValueView `json:"custom_fields_normalized,omitempty"`
	HourlyRate        *clockify.Rate         `json:"hourlyRate,omitempty"`
	IsLocked          bool                   `json:"isLocked,omitempty"`
	KioskID           string                 `json:"kioskId,omitempty"`
	Type              string                 `json:"type,omitempty"`
	UserID            string                 `json:"userId,omitempty"`
	WorkspaceID       string                 `json:"workspaceId,omitempty"`
	TimeInterval      clockify.TimeInterval  `json:"timeInterval"`
	Financials        EntryFinancials        `json:"financials"`
	Approval          *EntryApprovalView     `json:"approval,omitempty"`
	Invoicing         *EntryInvoicingView    `json:"invoicing,omitempty"`
	Entities          *EntryEntitiesView     `json:"entities,omitempty"`
	Audit             *EntryAuditView        `json:"audit,omitempty"`
}

EntryView is the model-facing time-entry envelope used by every tool that returns entries. It intentionally keeps the original clockify.TimeEntry JSON fields at the top level and appends a financials block so old clients keep working while agents can answer money questions without a second tool call.

type ErrorInfo

type ErrorInfo struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

ErrorInfo is the structured error detail in a ToolError: a stable code and a client-facing message.

type EstimateProgressView

type EstimateProgressView struct {
	TrackedDurationSeconds int64    `json:"tracked_duration_seconds"`
	EstimateSeconds        *int64   `json:"estimate_seconds,omitempty"`
	RemainingSeconds       *int64   `json:"remaining_seconds,omitempty"`
	PercentUsed            *float64 `json:"percent_used,omitempty"`
	OverEstimate           *bool    `json:"over_estimate,omitempty"`
	Source                 string   `json:"source"`
	Reason                 string   `json:"reason,omitempty"`
}

EstimateProgressView compares tracked time against the estimate: tracked and remaining seconds, percent used, and an over-estimate flag, with source/reason.

type ExpenseView

type ExpenseView map[string]any

ExpenseView is the pass-through expense projection: the raw upstream expense object as a generic map.

type FeatureLabel

type FeatureLabel struct {
	Key   string `json:"key"`
	Label string `json:"label"`
}

FeatureLabel pairs a raw workspace feature key with its human-readable label.

type FinancialRangeView

type FinancialRangeView struct {
	Start         string `json:"start,omitempty"`
	End           string `json:"end,omitempty"`
	DateRangeType string `json:"date_range_type,omitempty"`
	Timezone      string `json:"timezone,omitempty"`
}

FinancialRangeView describes the date window a financial rollup was computed over: start/end, the date-range type, and timezone.

type FindAndUpdateEntryData

type FindAndUpdateEntryData struct {
	Entry          EntryView               `json:"entry"`
	MatchedBy      map[string]any          `json:"matchedBy"`
	UpdatedFields  []string                `json:"updatedFields"`
	MatchedEntryID string                  `json:"matched_entry_id,omitempty"`
	Current        *TimeEntryUpdatePreview `json:"current,omitempty"`
	Proposed       map[string]any          `json:"proposed_changes,omitempty"`
	DryRun         bool                    `json:"dry_run,omitempty"`
	Note           string                  `json:"note,omitempty"`
	Validation     *ValidationView         `json:"validation,omitempty"`
}

FindAndUpdateEntryData is the structured payload for clockify_find_and_update_entry. Entry is the matched time entry; MatchedBy explains which finder predicate identified it; UpdatedFields lists the fields that actually changed. When dry_run:true is set, Current + Proposed + DryRun carry the preview-only diff so a downstream confirmation step can stage the mutation before applying.

type InvoiceItemView

type InvoiceItemView map[string]any

InvoiceItemView is the pass-through invoice-line-item projection as a generic map.

type InvoicePaymentView

type InvoicePaymentView map[string]any

InvoicePaymentView is the pass-through invoice-payment projection as a generic map.

type InvoiceReportView

type InvoiceReportView struct {
	Invoices         []InvoiceView  `json:"invoices"`
	AggregationScope string         `json:"aggregationScope"`
	PageTotalAmount  *MoneyView     `json:"pageTotalAmount,omitempty"`
	PageStatusCounts map[string]int `json:"pageStatusCounts,omitempty"`
	TotalAmount      *MoneyView     `json:"totalAmount,omitempty"`
	StatusCounts     map[string]int `json:"statusCounts,omitempty"`
	Summary          InvoiceSummary `json:"summary"`
	Raw              map[string]any `json:"raw,omitempty"`
}

InvoiceReportView is the shaped result of an invoice rollup: the per-invoice views, page-scoped and overall totals/status counts, and a Summary.

type InvoiceSettingsView

type InvoiceSettingsView map[string]any

InvoiceSettingsView is the pass-through invoice-settings projection as a generic map.

type InvoiceSummary

type InvoiceSummary struct {
	Count                 int            `json:"count"`
	ByStatus              map[string]int `json:"by_status,omitempty"`
	OverdueCount          int            `json:"overdue_count,omitempty"`
	ImportedTimeCount     int            `json:"imported_time_count,omitempty"`
	ImportedExpenseCount  int            `json:"imported_expense_count,omitempty"`
	Amount                *MoneyView     `json:"amount,omitempty"`
	Paid                  *MoneyView     `json:"paid,omitempty"`
	Balance               *MoneyView     `json:"balance,omitempty"`
	Currencies            []string       `json:"currencies,omitempty"`
	Source                string         `json:"source"`
	Reason                string         `json:"reason,omitempty"`
	SuggestedActionsCount int            `json:"suggested_actions_count,omitempty"`
}

InvoiceSummary aggregates an invoice set: total count, per-status and overdue counts, imported time/expense counts, normalized amount/paid/balance totals, and the currencies present.

type InvoiceView

type InvoiceView map[string]any

InvoiceView is the pass-through invoice projection: the raw upstream invoice object as a generic map.

type MoneyByCurrencyView

type MoneyByCurrencyView struct {
	Type     string         `json:"type,omitempty"`
	Currency string         `json:"currency,omitempty"`
	Money    MoneyView      `json:"money"`
	Raw      map[string]any `json:"raw,omitempty"`
}

MoneyByCurrencyView is a single per-currency money figure (with a type label, e.g. amount vs cost) extracted from a report entry's multi-currency totals.

type MoneyView

type MoneyView struct {
	AmountCents   int64  `json:"amount_cents"`
	AmountDecimal string `json:"amount_decimal"`
	Currency      string `json:"currency,omitempty"`
	Display       string `json:"display,omitempty"`
}

MoneyView is the LLM-facing envelope for any monetary value the MCP surfaces. The model receives all four fields:

  • amount_cents: int64 minor units (authoritative).
  • amount_decimal: string, two dp, signed (audit / direct render).
  • currency: ISO code from the source.
  • display: pre-rendered symbol form (e.g. "€43.21 EUR").

Callers that have only a JSON-number from the reports host should use MoneyFromReportNumber; callers with an int-cents value (the primary API) should use MoneyFromCents.

func DerivedEarnings

func DerivedEarnings(eff EffectiveRate, durationSeconds int64) (billable, cost MoneyView)

DerivedEarnings multiplies the effective hourly + cost rates by the given duration (in seconds) and returns the per-entry billable earnings and cost as MoneyViews. Both come back zero when no rate is set for that side. Rounding is to the nearest cent.

Math: rate is cents-per-hour; duration is seconds; result is

cents = round(rateCents * durationSeconds / 3600)

We use float intermediates and math.Round for the final cent — matching `CentsFromReportNumber`'s half-away-from-zero behaviour so the MCP-derived number agrees with Clockify's own.

func MoneyFromCents

func MoneyFromCents(cents int64, currency string) MoneyView

MoneyFromCents wraps an int64 cents value into a MoneyView.

func MoneyFromRate

func MoneyFromRate(r *clockify.Rate) MoneyView

MoneyFromRate is a nil-tolerant adapter for `*clockify.Rate`. A nil rate or an inherited sentinel returns the zero MoneyView so callers can decide whether to emit the field at all.

func MoneyFromReportNumber

func MoneyFromReportNumber(v float64, currency string) MoneyView

MoneyFromReportNumber converts a JSON-number cents value coming from the reports.api host (always integer-cents-as-float in practice) to MoneyView. Banker's rounding to int64 cents.

func (MoneyView) IsZero

func (m MoneyView) IsZero() bool

IsZero reports whether the MoneyView carries no information. Used by tool envelopes to decide whether to omit a money field rather than emit "$0.00" when no rate is actually known.

type NextAction

type NextAction struct {
	Tool   string         `json:"tool"`
	Args   map[string]any `json:"args,omitempty"`
	Reason string         `json:"reason,omitempty"`
}

NextAction suggests a follow-up tool call (with optional args and a reason) to chain after the current result.

type ProjectEstimateView

type ProjectEstimateView struct {
	EstimateRaw         any        `json:"estimate_raw,omitempty"`
	BudgetEstimateRaw   any        `json:"budget_estimate_raw,omitempty"`
	TimeEstimateRaw     any        `json:"time_estimate_raw,omitempty"`
	EstimateResetRaw    any        `json:"estimate_reset_raw,omitempty"`
	DurationRaw         string     `json:"duration_raw,omitempty"`
	DurationSeconds     *int64     `json:"duration_seconds,omitempty"`
	EstimateSeconds     *int64     `json:"estimate_seconds,omitempty"`
	TimeEstimateSeconds *int64     `json:"time_estimate_seconds,omitempty"`
	BudgetEstimate      *MoneyView `json:"budget_estimate,omitempty"`
}

ProjectEstimateView normalizes a project's or task's estimate fields: the raw upstream values plus their decoded duration/time-estimate seconds and budget.

type ProjectFinancials

type ProjectFinancials struct {
	Earned *MoneyView          `json:"earned,omitempty"`
	Cost   *MoneyView          `json:"cost,omitempty"`
	Profit *MoneyView          `json:"profit,omitempty"`
	Source string              `json:"source"`
	Reason string              `json:"reason,omitempty"`
	Range  *FinancialRangeView `json:"range,omitempty"`
}

ProjectFinancials holds a project's or task's earned/cost/profit money totals for a date range, along with the source/reason and the range they cover.

type ProjectMemberRateView

type ProjectMemberRateView struct {
	UserID           string         `json:"user_id"`
	TargetID         string         `json:"target_id,omitempty"`
	MembershipType   string         `json:"membership_type,omitempty"`
	MembershipStatus string         `json:"membership_status,omitempty"`
	HourlyRate       *clockify.Rate `json:"hourly_rate,omitempty"`
	CostRate         *clockify.Rate `json:"cost_rate,omitempty"`
	HourlyMoney      *MoneyView     `json:"hourly_money,omitempty"`
	CostMoney        *MoneyView     `json:"cost_money,omitempty"`
}

ProjectMemberRateView is the per-member rate projection within a ProjectRatesView: the membership identity plus hourly/cost rates (raw and as MoneyView).

type ProjectRatesView

type ProjectRatesView struct {
	ProjectHourly      *clockify.Rate          `json:"project_hourly,omitempty"`
	ProjectCost        *clockify.Rate          `json:"project_cost,omitempty"`
	ProjectHourlyMoney *MoneyView              `json:"project_hourly_money,omitempty"`
	ProjectCostMoney   *MoneyView              `json:"project_cost_money,omitempty"`
	Members            []ProjectMemberRateView `json:"members,omitempty"`
	Tasks              []TaskRateView          `json:"tasks,omitempty"`
}

ProjectRatesView aggregates a project's rates: project-level hourly/cost rates (raw and as MoneyView) plus per-member and per-task rate breakdowns.

type ProjectSummary

type ProjectSummary struct {
	ProjectID    string  `json:"projectId,omitempty"`
	ProjectName  string  `json:"projectName"`
	ClientID     string  `json:"clientId,omitempty"`
	ClientName   string  `json:"clientName,omitempty"`
	Entries      int     `json:"entries"`
	TotalSeconds int64   `json:"totalSeconds"`
	TotalHours   float64 `json:"totalHours"`
}

ProjectSummary is the per-project rollup row used by WeeklySummaryData and QuickReportData. ProjectID is omitempty so entries that did not resolve to a project (e.g. tracked with no project tag) still appear in the rollup keyed only by ProjectName.

type ProjectView

type ProjectView struct {
	ID                     string                       `json:"id"`
	Name                   string                       `json:"name"`
	ClientID               string                       `json:"clientId,omitempty"`
	ClientName             string                       `json:"clientName,omitempty"`
	Client                 any                          `json:"client,omitempty"`
	Color                  string                       `json:"color,omitempty"`
	Archived               bool                         `json:"archived"`
	Billable               bool                         `json:"billable,omitempty"`
	BudgetEstimate         any                          `json:"budgetEstimate,omitempty"`
	CostRate               *clockify.Rate               `json:"costRate,omitempty"`
	Currency               any                          `json:"currency,omitempty"`
	CustomFields           any                          `json:"customFields,omitempty"`
	CustomFieldsNormalized []CustomFieldValueView       `json:"custom_fields_normalized,omitempty"`
	Duration               string                       `json:"duration,omitempty"`
	Estimate               any                          `json:"estimate,omitempty"`
	EstimateReset          any                          `json:"estimateReset,omitempty"`
	Expenses               any                          `json:"expenses,omitempty"`
	Favorite               bool                         `json:"favorite,omitempty"`
	HourlyRate             *clockify.Rate               `json:"hourlyRate,omitempty"`
	Memberships            []clockify.ProjectMembership `json:"memberships,omitempty"`
	Note                   string                       `json:"note,omitempty"`
	Public                 bool                         `json:"public,omitempty"`
	Template               bool                         `json:"template,omitempty"`
	TimeEstimate           any                          `json:"timeEstimate,omitempty"`
	WorkspaceID            string                       `json:"workspaceId,omitempty"`

	Rates            ProjectRatesView     `json:"rates"`
	Financials       ProjectFinancials    `json:"financials"`
	Estimates        ProjectEstimateView  `json:"estimates"`
	EstimateProgress EstimateProgressView `json:"estimate_progress"`
	Tasks            []TaskView           `json:"tasks,omitempty"`
	ExpensesSummary  map[string]any       `json:"expenses_summary,omitempty"`
	RawHydrated      map[string]any       `json:"raw_hydrated,omitempty"`
}

ProjectView is the fully enriched project output returned by project tools: the core project fields plus normalized custom fields, rates, financials, estimates, estimate progress, and embedded task views.

type QuickReportData

type QuickReportData struct {
	Range               DateRange        `json:"range"`
	Totals              SummaryTotals    `json:"totals"`
	TopProject          *ProjectSummary  `json:"topProject,omitempty"`
	RunningEntries      []EntryView      `json:"runningEntries,omitempty"`
	EntriesSample       []EntryView      `json:"entriesSample,omitempty"`
	ProjectsRepresented int              `json:"projectsRepresented"`
	SuggestedActions    []ToolSuggestion `json:"suggestedActions"`
}

QuickReportData powers clockify_reports_summary: a single-glance snapshot with totals, the top project, any running entries, and a short entry sample so an agent can answer "what did I just do?" without a full detailed report round-trip.

type RateScope

type RateScope string

RateScope identifies which layer of the Clockify rate hierarchy supplied the effective rate for a given time entry. Returned to the model so it can explain *why* a particular earning amount is what it is, rather than only the final number.

const (
	RateScopeEntry         RateScope = "ENTRY"
	RateScopeTask          RateScope = "TASK"
	RateScopeProjectMember RateScope = "PROJECT_MEMBER"
	RateScopeProject       RateScope = "PROJECT"
	RateScopeWorkspace     RateScope = "WORKSPACE"
	RateScopeNone          RateScope = "NONE"
)

Rate scopes, ordered from most to least specific, identifying which level of the Clockify hierarchy supplied a time entry's effective rate.

type RecoveryHint

type RecoveryHint struct {
	Hint              string         `json:"hint"`
	Tool              string         `json:"tool,omitempty"`
	Args              map[string]any `json:"args,omitempty"`
	Retryable         bool           `json:"retryable,omitempty"`
	RetryAfterSeconds int            `json:"retryAfterSeconds,omitempty"`
}

RecoveryHint guides a caller toward recovering from a ToolError: a free-text hint, an optional suggested tool/args to retry, and retryability metadata.

type ReportApprovalSummary

type ReportApprovalSummary struct {
	WithApprovalRequest    int                          `json:"with_approval_request,omitempty"`
	WithoutApprovalRequest int                          `json:"without_approval_request,omitempty"`
	RequestIDs             []string                     `json:"request_ids,omitempty"`
	States                 map[string]int               `json:"states,omitempty"`
	DurationsByState       map[string]EntryDurationView `json:"durations_by_state,omitempty"`
}

ReportApprovalSummary aggregates approval coverage across a report's entries: counts with/without an approval request, per-state counts, and durations by state.

type ReportClientSummary

type ReportClientSummary struct {
	Client          EntryEntityRef        `json:"client"`
	EntrySummary    ReportEntrySummary    `json:"entry_summary"`
	Financials      EntryFinancials       `json:"financials"`
	ApprovalSummary ReportApprovalSummary `json:"approval_summary"`
}

ReportClientSummary is the per-client section of a report: the client reference with its entry summary, financials, and approval summary.

type ReportDefaults

type ReportDefaults struct {
	Timezone              string `json:"timezone,omitempty"`
	WeekStart             string `json:"week_start,omitempty"`
	DateFormat            string `json:"date_format,omitempty"`
	TimeFormat            string `json:"time_format,omitempty"`
	SummaryReportSettings any    `json:"summary_report_settings,omitempty"`
	Source                string `json:"source,omitempty"`
}

ReportDefaults captures a user's reporting preferences (timezone, week start, date/time formats, summary-report settings) used to default report arguments.

type ReportEntityRollup

type ReportEntityRollup struct {
	ID       string            `json:"id,omitempty"`
	Name     string            `json:"name,omitempty"`
	Email    string            `json:"email,omitempty"`
	Color    string            `json:"color,omitempty"`
	Count    int               `json:"count"`
	Duration EntryDurationView `json:"duration"`
}

ReportEntityRollup is the per-entity rollup row in a report's entity summary: the entity identity plus its entry count and total duration.

type ReportEntitySummary

type ReportEntitySummary struct {
	Users    []ReportEntityRollup `json:"users,omitempty"`
	Clients  []ReportEntityRollup `json:"clients,omitempty"`
	Projects []ReportEntityRollup `json:"projects,omitempty"`
	Tasks    []ReportEntityRollup `json:"tasks,omitempty"`
	Tags     []ReportEntityRollup `json:"tags,omitempty"`
}

ReportEntitySummary groups a report's entity rollups by dimension (users, clients, projects, tasks, tags).

type ReportEntrySummary

type ReportEntrySummary struct {
	Count                   int               `json:"count"`
	Duration                EntryDurationView `json:"duration"`
	BillableCount           int               `json:"billable_count,omitempty"`
	UnbillableCount         int               `json:"unbillable_count,omitempty"`
	BillableUnsetCount      int               `json:"billable_unset_count,omitempty"`
	LockedCount             int               `json:"locked_count,omitempty"`
	MissingDescriptionCount int               `json:"missing_description_count,omitempty"`
	MissingProjectCount     int               `json:"missing_project_count,omitempty"`
	MissingTaskCount        int               `json:"missing_task_count,omitempty"`
	ByType                  map[string]int    `json:"by_type,omitempty"`
}

ReportEntrySummary aggregates a set of report entries: total count and duration, billable/unbillable/unset and locked counts, data-quality miss counts, and a by-type breakdown.

type ReportEntryView

type ReportEntryView struct {
	ID                string                   `json:"id,omitempty"`
	Description       string                   `json:"description,omitempty"`
	Type              string                   `json:"type,omitempty"`
	Billable          *bool                    `json:"billable,omitempty"`
	BillableState     string                   `json:"billable_state,omitempty"`
	BillablePresent   bool                     `json:"billable_present,omitempty"`
	Locked            *bool                    `json:"locked,omitempty"`
	Duration          *EntryDurationView       `json:"duration,omitempty"`
	TimeInterval      map[string]any           `json:"time_interval,omitempty"`
	Entities          *EntryEntitiesView       `json:"entities,omitempty"`
	CustomFieldValues any                      `json:"customFieldValues,omitempty"`
	CustomFields      []CustomFieldValueView   `json:"custom_fields_normalized,omitempty"`
	Approval          *EntryApprovalView       `json:"approval,omitempty"`
	Invoicing         *EntryInvoicingView      `json:"invoicing,omitempty"`
	Audit             *EntryAuditView          `json:"audit,omitempty"`
	Financials        EntryFinancials          `json:"financials"`
	RateBreakdown     *ReportRateBreakdownView `json:"rate_breakdown,omitempty"`
	MoneyByCurrency   []MoneyByCurrencyView    `json:"money_by_currency,omitempty"`
}

ReportEntryView is the fully shaped projection of a single report entry row: core fields plus normalized duration, resolved entities, custom fields, and approval/invoicing/audit/financial/rate breakdowns.

type ReportGroupTotalsSummary

type ReportGroupTotalsSummary struct {
	Count       int               `json:"count"`
	Duration    EntryDurationView `json:"duration"`
	Financials  EntryFinancials   `json:"financials"`
	ByGroupType map[string]int    `json:"by_group_type,omitempty"`
}

ReportGroupTotalsSummary aggregates a report's group totals: the group count, summed duration and financials, and a by-group-type breakdown.

type ReportRateBreakdownView

type ReportRateBreakdownView struct {
	Rate         *MoneyView     `json:"rate,omitempty"`
	Amount       *MoneyView     `json:"amount,omitempty"`
	EarnedAmount *MoneyView     `json:"earnedAmount,omitempty"`
	EarnedRate   *MoneyView     `json:"earnedRate,omitempty"`
	CostAmount   *MoneyView     `json:"costAmount,omitempty"`
	CostRate     *MoneyView     `json:"costRate,omitempty"`
	Currency     string         `json:"currency,omitempty"`
	Raw          map[string]any `json:"raw,omitempty"`
}

ReportRateBreakdownView decomposes a report entry's monetary figures into rate and amount across the earned/cost dimensions, normalized to MoneyView.

type ReportRollupView

type ReportRollupView struct {
	Group              string                `json:"group,omitempty"`
	Level              int                   `json:"level,omitempty"`
	ID                 string                `json:"id,omitempty"`
	Name               string                `json:"name,omitempty"`
	Duration           EntryDurationView     `json:"duration"`
	Entries            int                   `json:"entries,omitempty"`
	Financials         EntryFinancials       `json:"financials"`
	MoneyByCurrency    []MoneyByCurrencyView `json:"money_by_currency,omitempty"`
	WeeklyDayBreakdown []WeeklyDayTotalView  `json:"weekly_day_breakdown,omitempty"`
	Children           []ReportRollupView    `json:"children,omitempty"`
}

ReportRollupView is a node in a hierarchical report rollup: a group's identity, aggregated duration/entries/financials, optional per-currency and weekly-day breakdowns, and nested child rollups.

type ReportTotalsSummary

type ReportTotalsSummary struct {
	Rows              int                   `json:"rows"`
	EntriesCount      int                   `json:"entries_count,omitempty"`
	TotalTime         *EntryDurationView    `json:"total_time,omitempty"`
	TotalBillableTime *EntryDurationView    `json:"total_billable_time,omitempty"`
	Financials        EntryFinancials       `json:"financials"`
	MoneyByCurrency   []MoneyByCurrencyView `json:"money_by_currency,omitempty"`
}

ReportTotalsSummary holds a report's overall totals: row and entry counts, total and billable time, financials, and per-currency money.

type Service

type Service struct {
	Client          *clockify.Client
	WorkspaceID     string
	DefaultTimezone *time.Location // from CLOCKIFY_TIMEZONE; nil falls back to time.Now().Location() for flexible date/time inputs.
	// WebhookValidateDNS, when true, makes CreateWebhook/UpdateWebhook
	// resolve the webhook host via the system resolver and reject any
	// reply that contains a private/reserved IP. Config defaults this
	// on for every profile so a hostname pointing at 169.254.169.254
	// (cloud-metadata) or 10.0.0.x cannot turn the Clockify webhook
	// delivery into an SSRF probe. Operators can explicitly opt out
	// for trusted air-gapped tests.
	WebhookValidateDNS bool
	// WebhookHostResolver overrides the LookupIPAddr call for tests.
	// nil = use net.DefaultResolver.
	WebhookHostResolver func(context.Context, string) ([]netip.Addr, error)
	// WebhookAllowedDomains is an optional escape-hatch list of webhook
	// hostnames that bypass the WebhookValidateDNS private-IP check.
	// Each entry is matched against the parsed URL's host (lowercased)
	// either by exact equality (`webhook.example.com`) or by suffix
	// when the entry begins with a dot (`.example.com` matches
	// `webhook.example.com` and `api.example.com` but NOT
	// `attacker.example.com.evil.com`). Empty list = no bypass; the
	// DNS check applies to every host.
	WebhookAllowedDomains []string
	// EnableRawTools allows the raw API fallback tools to run at all.
	EnableRawTools bool
	// EnableRawGet allows the raw API fallback to use GET. It is separate
	// from EnableRawWrites because workspace reads can expose sensitive state.
	EnableRawGet bool
	// EnableRawWrites allows the raw API fallback to use mutating HTTP
	// methods. The raw-tools gate must also be enabled.
	EnableRawWrites bool
	// RawWriteDocumentedOnly restricts raw mutating methods to routes present
	// in the generated OpenAPI allowlist. Raw GET remains unaffected.
	RawWriteDocumentedOnly bool
	// Toolset selects the startup registry surface. Empty/all exposes the
	// full owner workbench; smaller values are filtered by RegistryForToolset.
	Toolset string
	// ToolRateLimitDisabled is true only when the operator explicitly sets
	// CLOCKIFY_TOOL_RATE_LIMIT_PER_MINUTE=0.
	ToolRateLimitDisabled bool
	// ToolRateLimits reports the active per-risk invocation rate buckets.
	ToolRateLimits map[string]int
	// AuditLogPath is the optional local JSONL path used by the MCP runtime.
	AuditLogPath string
	// ConfirmationMode reports the central high-risk confirmation posture.
	ConfirmationMode string
	// Notifier delivers server→client notifications (progress, resource updates,
	// etc.) emitted by tool handlers. nil = drop silently.
	Notifier mcp.Notifier
	// EmitResourceUpdate publishes notifications/resources/updated for a URI
	// with an optional delta envelope. Wired to Server.NotifyResourceUpdated
	// so the subscription gate lives in the protocol core rather than in
	// every mutation handler. nil = drop silently.
	EmitResourceUpdate func(uri string, delta mcp.ResourceUpdateDelta)
	// EmitResourceListChanged publishes notifications/resources/list_changed
	// when the set of available resources changes (e.g. a new demo-run
	// resource appears). nil disables the notification.
	EmitResourceListChanged func()
	// SubscriptionGate reports whether any client is currently subscribed
	// to a URI. When wired (Server.HasResourceSubscription),
	// emitResourceUpdate short-circuits before the ReadResource round-trip
	// so unsubscribed mutations don't pay for a redundant fetch.
	SubscriptionGate func(uri string) bool
	// EntryFinancialReports forces entry financial enrichment to call the
	// reports host even when the client is pointed at a non-canonical base URL.
	// Production Clockify calls auto-enable this path; tests and local proxies
	// opt in explicitly so unrelated fake handlers do not receive surprise
	// reports-api requests.
	EntryFinancialReports bool
	// contains filtered or unexported fields
}

Service holds the runtime state for all Clockify tools: the HTTP client, the pinned workspace ID, timezone/webhook-safety configuration, the raw-fallback enablement gates, and the cached resolver/resource emitter state. It is the receiver for every tool handler.

func New

func New(client *clockify.Client, workspaceID string) *Service

New returns a Service bound to the given Clockify client and pinned workspace ID, with webhook DNS validation enabled by default and the resource emitter caches initialized.

func (*Service) AddUserToGroup

func (s *Service) AddUserToGroup(ctx context.Context, args map[string]any) (ToolResult, error)

AddUserToGroup adds a user to a user group.

func (*Service) ArchiveProjects

func (s *Service) ArchiveProjects(ctx context.Context, args map[string]any) (ToolResult, error)

ArchiveProjects backs clockify_projects_archive: it archives one or more projects by ID, removing them from active work.

func (*Service) AssignProjectMemberships

func (s *Service) AssignProjectMemberships(ctx context.Context, args map[string]any) (ToolResult, error)

AssignProjectMemberships adds or (when remove is true) removes the given user_ids / user_groups from a project's membership via POST, without replacing the full membership array.

func (*Service) AssignmentReport

func (s *Service) AssignmentReport(ctx context.Context, args map[string]any) (ToolResult, error)

AssignmentReport runs the scheduling-assignment report: it groups recurring assignments over a date range and compares scheduled vs available vs tracked time (with money figures when Reports access is available).

func (*Service) AttendanceReport

func (s *Service) AttendanceReport(ctx context.Context, args map[string]any) (ToolResult, error)

AttendanceReport handles clockify_reports_attendance: it runs Clockify's attendance report; raw amounts are minor units and meta.totalAmount carries the normalized major-unit totals.

func (*Service) AuditLogsSearch

func (s *Service) AuditLogsSearch(ctx context.Context, args map[string]any) (ToolResult, error)

AuditLogsSearch backs clockify_audit_logs_search. It posts an AuditLogGetRequestV1 filter to the dedicated Clockify audit-log host. The live API returns a bare JSON array of audit-log entries, not the PageableV1ListAuditLogDtoV1 envelope the OpenAPI document describes; a live probe against the sacrificial workspace confirmed the bare-array shape.

func (*Service) ClientsCreate

func (s *Service) ClientsCreate(ctx context.Context, args map[string]any) (any, error)

ClientsCreate handles clockify_clients_create: it creates a client by name and returns its ID plus a next-action suggestion to create a project for it.

func (*Service) ClientsList

func (s *Service) ClientsList(ctx context.Context, args map[string]any) (any, error)

ClientsList handles clockify_clients_list: it lists workspace clients with pagination and optional auto-pagination, returning compact pagination meta.

func (*Service) ClockifyCreateWorkPackage

func (s *Service) ClockifyCreateWorkPackage(ctx context.Context, args map[string]any) (any, error)

ClockifyCreateWorkPackage handles clockify_create_work_package: it creates or reuses a client/project/task/tag work package from names or IDs.

func (*Service) ClockifyDemoCleanup

func (s *Service) ClockifyDemoCleanup(ctx context.Context, args map[string]any) (any, error)

ClockifyDemoCleanup handles clockify_demo_cleanup: it deletes the deterministic demo objects for a run ID prefix, continuing through partial failures.

func (*Service) ClockifyDemoSeed

func (s *Service) ClockifyDemoSeed(ctx context.Context, args map[string]any) (any, error)

ClockifyDemoSeed handles clockify_demo_seed: it creates or reuses deterministic demo client/project/task/tag/time-entry objects keyed by a run ID prefix.

func (*Service) ClockifyFixEntry

func (s *Service) ClockifyFixEntry(ctx context.Context, args map[string]any) (any, error)

ClockifyFixEntry handles clockify_fix_entry: it finds one entry by ID or strict filters, then updates the selected fields, delegating to FindAndUpdateEntry.

func (*Service) ClockifyInvoiceClientWork

func (s *Service) ClockifyInvoiceClientWork(ctx context.Context, args map[string]any) (any, error)

ClockifyInvoiceClientWork handles clockify_invoice_client_work: the billing workflow that creates an invoice for a client from a name or ID, degrading gracefully when invoicing is unavailable and supporting a dry_run preview.

func (*Service) ClockifyLogWork

func (s *Service) ClockifyLogWork(ctx context.Context, args map[string]any) (any, error)

ClockifyLogWork handles clockify_log_work: it logs a finished time entry using human-friendly names or returned IDs.

func (*Service) ClockifyRecordExpense

func (s *Service) ClockifyRecordExpense(ctx context.Context, args map[string]any) (any, error)

ClockifyRecordExpense handles clockify_record_expense: the billing workflow that records an expense with category, project, task, and user names or IDs, supporting a dry_run preview.

func (*Service) ClockifyRequestTimeOff

func (s *Service) ClockifyRequestTimeOff(ctx context.Context, args map[string]any) (any, error)

ClockifyRequestTimeOff handles clockify_request_time_off: the admin workflow that creates a time-off request from a policy name or ID (resolving names across all pages); it can enter approval workflows and affect PTO balances and supports a dry_run preview.

func (*Service) ClockifyReviewDay

func (s *Service) ClockifyReviewDay(ctx context.Context, args map[string]any) (any, error)

ClockifyReviewDay handles clockify_review_day: it reviews one day of work (defaulting to today) and returns totals, issues, and next actions.

func (*Service) ClockifyReviewWeek

func (s *Service) ClockifyReviewWeek(ctx context.Context, args map[string]any) (any, error)

ClockifyReviewWeek handles clockify_review_week: it reviews one week of work (defaulting to the current week) and returns totals, issues, and next actions.

func (*Service) ClockifyScheduleWork

func (s *Service) ClockifyScheduleWork(ctx context.Context, args map[string]any) (any, error)

ClockifyScheduleWork handles clockify_schedule_work: the admin scheduling workflow that creates an assignment from user/project names or IDs, failing fast with one clear message when either is missing, and supporting a dry_run preview.

func (*Service) ClockifySetupWebhook

func (s *Service) ClockifySetupWebhook(ctx context.Context, args map[string]any) (any, error)

ClockifySetupWebhook handles clockify_setup_webhook: the external-side-effect workflow that creates a webhook subscription for this workspace and future outbound deliveries, supporting a dry_run preview.

func (*Service) ClockifyStartWork

func (s *Service) ClockifyStartWork(ctx context.Context, args map[string]any) (any, error)

ClockifyStartWork handles clockify_start_work: it starts a running work timer using names or IDs.

func (*Service) ClockifyStatus

func (s *Service) ClockifyStatus(ctx context.Context, _ map[string]any) (any, error)

ClockifyStatus handles clockify_status: it reports the current user, pinned workspace, timezone/week-start, any running timer, feature status, and the recommended first tools.

func (*Service) ClockifyStopWork

func (s *Service) ClockifyStopWork(ctx context.Context, args map[string]any) (any, error)

ClockifyStopWork handles clockify_stop_work: it stops the current running work timer.

func (*Service) ClockifySwitchWork

func (s *Service) ClockifySwitchWork(ctx context.Context, args map[string]any) (any, error)

ClockifySwitchWork handles clockify_switch_work: it switches the running timer to another work item using names or IDs.

func (*Service) ClockifyToolsGuide

func (s *Service) ClockifyToolsGuide(_ context.Context, _ map[string]any) (any, error)

ClockifyToolsGuide handles clockify_tools_guide: it returns the grouped workflow and domain tools with common-task guidance.

func (*Service) CreateCustomField

func (s *Service) CreateCustomField(ctx context.Context, args map[string]any) (ToolResult, error)

CreateCustomField handles clockify_custom_fields_create: it creates a custom field of a valid type (TXT, NUMBER, DROPDOWN_SINGLE, DROPDOWN_MULTIPLE, CHECKBOX, or LINK), validating allowedValues for dropdown types.

func (*Service) CreateHoliday

func (s *Service) CreateHoliday(ctx context.Context, args map[string]any) (ToolResult, error)

CreateHoliday handles clockify_holidays_create: it creates a holiday, requiring name + start_date and at least one user_ids or user_group_ids assignee, and rejecting an unparseable date locally.

func (*Service) CreateProjectFromTemplate

func (s *Service) CreateProjectFromTemplate(ctx context.Context, args map[string]any) (ToolResult, error)

CreateProjectFromTemplate creates a new project seeded from an existing project template.

func (*Service) CreateProjectTemplate

func (s *Service) CreateProjectTemplate(ctx context.Context, args map[string]any) (ToolResult, error)

CreateProjectTemplate handles clockify_projects_templates_create: it creates a new project template in the workspace.

func (*Service) CreateTag

func (s *Service) CreateTag(ctx context.Context, args map[string]any) (ToolResult, error)

CreateTag handles clockify_tags_create: it creates a tag by name in the pinned workspace.

func (*Service) CreateUserGroup

func (s *Service) CreateUserGroup(ctx context.Context, args map[string]any) (ToolResult, error)

CreateUserGroup creates a new user group.

func (*Service) CreateUserGroupAdmin

func (s *Service) CreateUserGroupAdmin(ctx context.Context, args map[string]any) (ToolResult, error)

CreateUserGroupAdmin handles clockify_groups_create: it creates a user group with an optional set of member user IDs.

func (*Service) CreateWebhook

func (s *Service) CreateWebhook(ctx context.Context, args map[string]any) (ToolResult, error)

CreateWebhook creates a new webhook with URL validation.

func (*Service) CurrentUser

func (s *Service) CurrentUser(ctx context.Context) (ToolResult, error)

CurrentUser handles clockify_users_profile: it returns the current Clockify user.

func (*Service) DeactivateUser

func (s *Service) DeactivateUser(ctx context.Context, args map[string]any) (ToolResult, error)

DeactivateUser deactivates a user. Supports dry-run (confirm pattern).

func (*Service) DeleteClient

func (s *Service) DeleteClient(ctx context.Context, args map[string]any) (ToolResult, error)

DeleteClient archives the client if it is still active, then deletes it. Clockify rejects DELETE on active clients (the active rule is the same as for projects), and the PUT archive validator additionally requires the existing name in the body. The implementation mirrors the rawArchiveAndDeleteClient cleanup helper in tests/.

func (*Service) DeleteCustomField

func (s *Service) DeleteCustomField(ctx context.Context, args map[string]any) (ToolResult, error)

DeleteCustomField handles clockify_custom_fields_delete: it deletes a custom field by ID and supports a dry_run preview.

func (*Service) DeleteEntry

func (s *Service) DeleteEntry(ctx context.Context, args map[string]any) (ToolResult, error)

DeleteEntry deletes a time entry by ID.

func (*Service) DeleteHoliday

func (s *Service) DeleteHoliday(ctx context.Context, args map[string]any) (ToolResult, error)

DeleteHoliday handles clockify_holidays_delete: it deletes a holiday by ID and supports a dry_run preview.

func (*Service) DeleteProject

func (s *Service) DeleteProject(ctx context.Context, args map[string]any) (ToolResult, error)

DeleteProject archives the project if still active, then deletes it. Clockify rejects DELETE on active projects (the archive validator additionally requires the existing name in the body). Mirrors clients.DeleteClient's archive-first pattern; both resources share the same upstream constraint.

func (*Service) DeleteTag

func (s *Service) DeleteTag(ctx context.Context, args map[string]any) (ToolResult, error)

DeleteTag deletes a tag by ID or exact name. Clockify's DELETE /workspaces/{ws}/tags/{id} works directly on active tags — no archive step is required (unlike clients). Supports dry_run.

func (*Service) DeleteTask

func (s *Service) DeleteTask(ctx context.Context, args map[string]any) (ToolResult, error)

DeleteTask deletes a task by project + task reference (ID or name). Clockify requires tasks to be DONE before DELETE, so active tasks are first updated with the existing full-replacement shape plus status=DONE.

func (*Service) DeleteUserGroup

func (s *Service) DeleteUserGroup(ctx context.Context, args map[string]any) (ToolResult, error)

DeleteUserGroup deletes a user group. Supports dry-run (minimal fallback).

func (*Service) DeleteUserGroupAdmin

func (s *Service) DeleteUserGroupAdmin(ctx context.Context, args map[string]any) (ToolResult, error)

DeleteUserGroupAdmin handles clockify_groups_delete: it deletes a user group by ID and supports a dry_run preview.

func (*Service) DeleteWebhook

func (s *Service) DeleteWebhook(ctx context.Context, args map[string]any) (ToolResult, error)

DeleteWebhook deletes a webhook. Supports dry-run (preview via GET).

func (*Service) DetailedReport

func (s *Service) DetailedReport(ctx context.Context, args map[string]any) (ToolResult, error)

DetailedReport handles clockify_reports_detailed: it runs Clockify's detailed time report over the requested range.

func (*Service) EmitProgress

func (s *Service) EmitProgress(ctx context.Context, progress, total float64, message string)

EmitProgress publishes a notifications/progress if a progressToken was supplied with the current tools/call and the Service has a Notifier wired. No-op otherwise. total < 0 signals an indeterminate total.

func (*Service) EntityChangesList

func (s *Service) EntityChangesList(ctx context.Context, args map[string]any) (ToolResult, error)

EntityChangesList backs clockify_entity_changes_list. It reads the experimental entities/{created,updated,deleted} feed on the primary host. The live API returns a bare array of change documents; the OpenAPI envelope shape was never observed in practice, so the handler decodes a plain array and surfaces a recovery envelope if Clockify ever changes it.

func (*Service) EntriesCreate

func (s *Service) EntriesCreate(ctx context.Context, args map[string]any) (any, error)

EntriesCreate handles clockify_entries_create: it creates a time entry, honoring dry_run with a validated payload preview and emitting future-entry warnings, then returns the created entry and the affected IDs.

func (*Service) EntriesList

func (s *Service) EntriesList(ctx context.Context, args map[string]any) (any, error)

EntriesList handles clockify_entries_list: it lists the current user's time entries with pagination and optional auto-pagination, capturing the resolved user ID into the result IDs.

func (*Service) EntriesMarkInvoiced

func (s *Service) EntriesMarkInvoiced(ctx context.Context, args map[string]any) (ToolResult, error)

EntriesMarkInvoiced handles clockify_entries_mark_invoiced: it marks the given time entries as invoiced or not invoiced.

func (*Service) EntriesRunning

func (s *Service) EntriesRunning(ctx context.Context, _ map[string]any) (any, error)

EntriesRunning handles clockify_entries_running: it returns the user's currently running time entry, or an empty entry result when no timer is running.

func (*Service) EntriesTimerStart

func (s *Service) EntriesTimerStart(ctx context.Context, args map[string]any) (any, error)

EntriesTimerStart handles clockify_entries_timer_start: it starts a running time-entry timer for the current user, wrapping StartTimerArgs in the standard domain result.

func (*Service) EntriesTimerStatus

func (s *Service) EntriesTimerStatus(ctx context.Context, _ map[string]any) (any, error)

EntriesTimerStatus handles clockify_entries_timer_status: it reports whether the current user has a running timer, wrapping TimerStatus in the standard domain result.

func (*Service) EntriesTimerStop

func (s *Service) EntriesTimerStop(ctx context.Context, args map[string]any) (any, error)

EntriesTimerStop handles clockify_entries_timer_stop: it stops the current user's running timer, preserving the clean no-timer-running no-op shape and otherwise wrapping StopTimer in the standard domain result.

func (*Service) EntriesTimerSwitch

func (s *Service) EntriesTimerSwitch(ctx context.Context, args map[string]any) (any, error)

EntriesTimerSwitch handles clockify_entries_timer_switch: it switches the running timer to another project, wrapping SwitchProject in the standard domain result.

func (*Service) ExpenseReport

func (s *Service) ExpenseReport(ctx context.Context, args map[string]any) (ToolResult, error)

ExpenseReport handles clockify_reports_expense: it runs Clockify's detailed expense report over the requested range.

func (*Service) FindAndUpdateEntry

func (s *Service) FindAndUpdateEntry(ctx context.Context, args map[string]any) (any, error)

FindAndUpdateEntry backs clockify_fix_entry: it locates one time entry by ID or strict filters, then applies the selected field updates.

func (*Service) FirstSliceRegistry

func (s *Service) FirstSliceRegistry() []mcp.ToolDescriptor

FirstSliceRegistry returns the "first slice" of domain tool descriptors (clients, projects, tasks, and related CRUD) that the full-access registry appends after the workflow tools. Duplicate workflow-annotated tools are deduped by buildFullAccessRegistry, so they are intentionally not re-listed here.

func (*Service) FullAccessRegistryChecked added in v0.4.0

func (s *Service) FullAccessRegistryChecked() ([]mcp.ToolDescriptor, error)

FullAccessRegistryChecked builds (once, memoized) and returns the full 156-tool registry in the canonical order (workflow, domain, raw fallback), validating it via ValidateRegistry. It returns an error rather than panicking when descriptor construction or validation fails.

func (*Service) GetClientWithArgs

func (s *Service) GetClientWithArgs(ctx context.Context, args map[string]any) (ToolResult, error)

GetClientWithArgs handles clockify_clients_get: it resolves the client by name or ID and returns the enriched client view.

func (*Service) GetCustomField

func (s *Service) GetCustomField(ctx context.Context, args map[string]any) (ToolResult, error)

GetCustomField handles clockify_custom_fields_get: it returns a custom-field definition by ID from the pinned workspace.

func (*Service) GetEntry

func (s *Service) GetEntry(ctx context.Context, args map[string]any) (ToolResult, error)

GetEntry retrieves a single time entry by ID.

func (*Service) GetHoliday

func (s *Service) GetHoliday(ctx context.Context, args map[string]any) (ToolResult, error)

GetHoliday handles clockify_holidays_get: it returns one holiday by ID from the pinned workspace.

func (*Service) GetMemberProfile

func (s *Service) GetMemberProfile(ctx context.Context, args map[string]any) (ToolResult, error)

GetMemberProfile returns a workspace-scoped member profile for a user.

func (*Service) GetProject

func (s *Service) GetProject(ctx context.Context, args map[string]any) (ToolResult, error)

GetProject handles clockify_projects_get: it resolves a project by name or ID and returns the enriched project view.

func (*Service) GetProjectTemplate

func (s *Service) GetProjectTemplate(ctx context.Context, args map[string]any) (ToolResult, error)

GetProjectTemplate returns a project template by its project ID from the pinned workspace.

func (*Service) GetTag

func (s *Service) GetTag(ctx context.Context, args map[string]any) (ToolResult, error)

GetTag fetches a single tag by ID or exact name.

func (*Service) GetTask

func (s *Service) GetTask(ctx context.Context, args map[string]any) (ToolResult, error)

GetTask fetches a single task by ID or exact name within a project. project (name or ID) and task (ID or name) are both required.

func (*Service) GetUserGroup

func (s *Service) GetUserGroup(ctx context.Context, args map[string]any) (ToolResult, error)

GetUserGroup handles clockify_groups_get: it returns a user group by ID from the pinned workspace.

func (*Service) GetWebhook

func (s *Service) GetWebhook(ctx context.Context, args map[string]any) (ToolResult, error)

GetWebhook retrieves a single webhook by ID.

func (*Service) GetWorkspace

func (s *Service) GetWorkspace(ctx context.Context) (ToolResult, error)

GetWorkspace handles clockify_workspace_settings: it reads the pinned workspace's settings.

func (*Service) InviteUser

func (s *Service) InviteUser(ctx context.Context, args map[string]any) (ToolResult, error)

InviteUser invites a single user to the workspace by email (send_email defaults to true), supporting a dry_run preview.

func (*Service) InvoicesInfo

func (s *Service) InvoicesInfo(ctx context.Context, args map[string]any) (ToolResult, error)

InvoicesInfo backs clockify_invoices_info: a bulk, paged invoice query via POST /invoices/info. Unlike clockify_invoices_list it returns the workspace total (filtered by the status filter) so a caller can compute has_more; unlike clockify_invoice_report it returns raw invoice rows, not money aggregates.

func (*Service) ListCustomFields

func (s *Service) ListCustomFields(ctx context.Context, args map[string]any) (ToolResult, error)

ListCustomFields handles clockify_custom_fields_list: it lists the workspace's custom-field definitions with optional pagination.

func (*Service) ListEntries

func (s *Service) ListEntries(ctx context.Context, args map[string]any) (ToolResult, error)

ListEntries returns recent time entries with optional filtering by date range, project, and pagination.

func (*Service) ListHolidays

func (s *Service) ListHolidays(ctx context.Context) (ToolResult, error)

ListHolidays handles clockify_holidays_list: it returns every holiday configured in the workspace on a single page.

func (*Service) ListHolidaysInPeriod

func (s *Service) ListHolidaysInPeriod(ctx context.Context, args map[string]any) (ToolResult, error)

ListHolidaysInPeriod handles clockify_holidays_list_for_user_period: it lists the holidays assigned to a user across a date period, returning the full set on a single page.

func (*Service) ListProjectMemberships

func (s *Service) ListProjectMemberships(ctx context.Context, args map[string]any) (ToolResult, error)

ListProjectMemberships handles clockify_projects_memberships_list: it returns the project's memberships read from the hydrated project record, as a single page.

func (*Service) ListProjectTemplates

func (s *Service) ListProjectTemplates(ctx context.Context, args map[string]any) (ToolResult, error)

ListProjectTemplates handles clockify_list_project_templates: it lists the pinned workspace's template projects (is-template=true), paginated via page/page_size.

func (*Service) ListResourceTemplates

func (s *Service) ListResourceTemplates(_ context.Context) ([]mcp.ResourceTemplate, error)

ListResourceTemplates returns the parametric URI templates clients can dereference by substituting concrete IDs.

func (*Service) ListResources

func (s *Service) ListResources(ctx context.Context) ([]mcp.Resource, error)

ListResources returns a small, immediately-navigable set of concrete resources pinned to the Service's current workspace. Parametric resources (per-id entry, project, weekly report) live in ListResourceTemplates.

func (*Service) ListTags

func (s *Service) ListTags(ctx context.Context, args map[string]any) (ToolResult, error)

ListTags handles clockify_tags_list: it lists tags in the pinned workspace with pagination.

func (*Service) ListUserGroups

func (s *Service) ListUserGroups(ctx context.Context, args map[string]any) (ToolResult, error)

ListUserGroups returns user groups for the workspace.

func (*Service) ListUserGroupsAdmin

func (s *Service) ListUserGroupsAdmin(ctx context.Context, args map[string]any) (ToolResult, error)

ListUserGroupsAdmin handles clockify_list_user_groups_admin: it lists the pinned workspace's user groups with the admin-scope query options, paginated via page/page_size.

func (*Service) ListUserManagers

func (s *Service) ListUserManagers(ctx context.Context, args map[string]any) (ToolResult, error)

ListUserManagers returns managers assigned to a workspace user.

func (*Service) ListUsers

func (s *Service) ListUsers(ctx context.Context, args map[string]any) (ToolResult, error)

ListUsers handles clockify_users_list: it lists users in the pinned workspace with pagination.

func (*Service) ListWebhookEvents

func (s *Service) ListWebhookEvents(ctx context.Context, _ map[string]any) (ToolResult, error)

ListWebhookEvents returns the static enum of webhook event types the Clockify webhooks API accepts. The upstream exposes no listing endpoint — see findings/webhooks.md (#15).

func (*Service) ListWebhookLogs

func (s *Service) ListWebhookLogs(ctx context.Context, args map[string]any) (ToolResult, error)

ListWebhookLogs returns delivery attempts for a webhook via the documented POST logs search route.

func (*Service) ListWebhooks

func (s *Service) ListWebhooks(ctx context.Context, args map[string]any) (ToolResult, error)

ListWebhooks returns webhooks for the workspace.

func (*Service) MoneyReport

func (s *Service) MoneyReport(ctx context.Context, args map[string]any) (ToolResult, error)

MoneyReport handles clockify_reports_money: it runs the summary report tuned for billing-rate money breakdowns by user or project.

func (*Service) ProjectsCreate

func (s *Service) ProjectsCreate(ctx context.Context, args map[string]any) (any, error)

ProjectsCreate handles clockify_projects_create: it creates a project (with optional client linkage) and returns its ID plus a next-action suggestion to add a task.

func (*Service) ProjectsList

func (s *Service) ProjectsList(ctx context.Context, args map[string]any) (any, error)

ProjectsList handles clockify_projects_list: it lists workspace projects (compact view) with pagination and optional auto-pagination.

func (*Service) QuickReport

func (s *Service) QuickReport(ctx context.Context, args map[string]any) (ToolResult, error)

QuickReport runs a local time-entries-wrapper rollup over the last N days (default 7), returning totals, top/per-project summaries, optional entry samples, and any running entries.

func (*Service) RawAPIGet

func (s *Service) RawAPIGet(ctx context.Context, args map[string]any) (any, error)

RawAPIGet handles clockify_api_get: the raw GET fallback for documented Clockify endpoints, workspace-fenced to /user or the pinned workspace.

func (*Service) RawAPIRequest

func (s *Service) RawAPIRequest(ctx context.Context, args map[string]any) (any, error)

RawAPIRequest handles the raw method/path fallback tool: it requires an explicit HTTP method in args and dispatches through the workspace-fenced raw API path, subject to the raw-tools and raw-write enablement gates.

func (*Service) ReadResource

func (s *Service) ReadResource(ctx context.Context, uri string) ([]mcp.ResourceContents, error)

ReadResource parses a clockify:// URI and fetches the underlying entity from Clockify, returning it as a single JSON-encoded ResourceContents entry. Unknown or malformed URIs return a -32602-equivalent error.

func (*Service) RegistryForToolset

func (s *Service) RegistryForToolset(toolset string) []mcp.ToolDescriptor

RegistryForToolset returns the one-user startup registry for a narrower advertised surface. The "all" and empty paths are intentionally identical to FullAccessRegistryChecked so the canonical 156-tool product contract stays intact.

func (*Service) RemoveUserFromGroup

func (s *Service) RemoveUserFromGroup(ctx context.Context, args map[string]any) (ToolResult, error)

RemoveUserFromGroup removes a user from a user group. Supports dry-run (minimal fallback).

func (*Service) ResolveName

func (s *Service) ResolveName(ctx context.Context, args map[string]any) (ToolResult, error)

ResolveName handles the name-resolution tool: it resolves an entity_type + name_or_id pair to a concrete entity, surfacing the one-user tool guide as the recovery action on failure.

func (*Service) ResolveWorkspaceID

func (s *Service) ResolveWorkspaceID(ctx context.Context) (string, error)

ResolveWorkspaceID returns the pinned workspace ID, validating it; when none is configured it auto-detects from /workspaces (caching the result) and errors if zero or multiple workspaces are available.

func (*Service) SchedulingPublish

func (s *Service) SchedulingPublish(ctx context.Context, args map[string]any) (ToolResult, error)

SchedulingPublish backs clockify_scheduling_publish. Scheduling assignment create/update produce drafts; this is the separate step that publishes every draft assignment in the start..end window. The Clockify endpoint returns no body, so the receipt is synthesised from the request (Axiom 8).

func (*Service) SetCustomFieldValue

func (s *Service) SetCustomFieldValue(ctx context.Context, args map[string]any) (ToolResult, error)

SetCustomFieldValue handles clockify_custom_fields_set_value: it sets a custom field value on a project or time entry, routing through the documented custom-fields route for projects and the entry route for entries.

func (*Service) SetProjectMemberships

func (s *Service) SetProjectMemberships(ctx context.Context, args map[string]any) (ToolResult, error)

SetProjectMemberships sets a project's membership from a user_ids array (with an optional shared hourly_rate), building the membership objects and delegating to UpdateProjectMemberships.

func (*Service) StartTimer

func (s *Service) StartTimer(ctx context.Context, projectID, projectRef, description string) (ToolResult, error)

StartTimer starts a running timer for the current user from explicit project ID/reference and description, delegating to the internal startTimer.

func (*Service) StartTimerArgs

func (s *Service) StartTimerArgs(ctx context.Context, args map[string]any) (ToolResult, error)

StartTimerArgs starts a running timer for the current user from a raw args map, delegating to the internal startTimer.

func (*Service) StopTimer

func (s *Service) StopTimer(ctx context.Context, args map[string]any) (any, error)

StopTimer stops the current user's running timer. With no running timer it is a clean no-op (stopped:false), retrying briefly to absorb a just-started timer, and supports a dry_run preview.

func (*Service) SummaryReport

func (s *Service) SummaryReport(ctx context.Context, args map[string]any) (ToolResult, error)

SummaryReport handles clockify_reports_summary: it runs Clockify's summary report for simple time totals over the requested range/grouping.

func (*Service) SwitchProject

func (s *Service) SwitchProject(ctx context.Context, args map[string]any) (ToolResult, error)

SwitchProject stops the current running timer and starts a new one on the target project, backing the switch-work timer workflow.

func (*Service) TagsCreate

func (s *Service) TagsCreate(ctx context.Context, args map[string]any) (any, error)

TagsCreate handles clockify_tags_create: it creates a tag by name and returns its ID.

func (*Service) TagsList

func (s *Service) TagsList(ctx context.Context, args map[string]any) (any, error)

TagsList handles clockify_tags_list: it lists workspace tags with pagination and optional auto-pagination.

func (*Service) TasksCreate

func (s *Service) TasksCreate(ctx context.Context, args map[string]any) (any, error)

TasksCreate handles clockify_tasks_create: it resolves the project from args and creates a task by name under it, returning the new task ID.

func (*Service) TasksList

func (s *Service) TasksList(ctx context.Context, args map[string]any) (any, error)

TasksList handles clockify_tasks_list: it resolves the project from args and lists its tasks with pagination and optional auto-pagination.

func (*Service) TestWebhook

func (s *Service) TestWebhook(_ context.Context, args map[string]any) (ToolResult, error)

TestWebhook reports the absence of a Clockify webhook test-send endpoint.

func (*Service) TimerStatus

func (s *Service) TimerStatus(ctx context.Context) (ToolResult, error)

TimerStatus reports whether the current user has a running timer and returns it when present.

func (*Service) TimesheetReview

func (s *Service) TimesheetReview(ctx context.Context, args map[string]any) (ToolResult, error)

TimesheetReview handles the timesheet-review workflow: it summarizes the user's entries over a date range, detects issues (gaps, overlaps, missing metadata), and returns suggested corrective actions.

func (*Service) UnbilledForClient

func (s *Service) UnbilledForClient(ctx context.Context, args map[string]any) (ToolResult, error)

UnbilledForClient handles the unbilled-for-client composite tool: it resolves the client and returns its unbilled work over a date range with summaries, financials, and suggested invoicing actions.

func (*Service) UpdateClient

func (s *Service) UpdateClient(ctx context.Context, args map[string]any) (ToolResult, error)

UpdateClient performs a fetch-then-merge update of a client. Clockify's PUT /clients/{id} is a full replacement (omitted fields get nulled server-side), so we GET the existing client, layer caller-provided changes over the fetched object, and PUT the complete merged shape back. Caller-supplied empty strings are treated as "do not change" (use the dedicated `archived` boolean flag to flip archival state).

func (*Service) UpdateCustomField

func (s *Service) UpdateCustomField(ctx context.Context, args map[string]any) (ToolResult, error)

UpdateCustomField handles clockify_custom_fields_update: it updates an existing custom-field definition by ID.

func (*Service) UpdateEntry

func (s *Service) UpdateEntry(ctx context.Context, args map[string]any) (ToolResult, error)

UpdateEntry performs a fetch-then-update of a time entry, merging caller fields over the existing values.

func (*Service) UpdateHoliday

func (s *Service) UpdateHoliday(ctx context.Context, args map[string]any) (ToolResult, error)

UpdateHoliday handles clockify_holidays_update: it is a partial update keyed by holiday_id, merging unspecified fields from the existing record.

func (*Service) UpdateMemberProfile

func (s *Service) UpdateMemberProfile(ctx context.Context, args map[string]any) (ToolResult, error)

UpdateMemberProfile updates live-supported workspace member profile fields.

func (*Service) UpdateProject

func (s *Service) UpdateProject(ctx context.Context, args map[string]any) (ToolResult, error)

UpdateProject performs a fetch-then-merge update of a project. Clockify's PUT /projects/{id} replaces the full record (omitted optional fields are nulled), so we GET the existing project, layer caller-provided changes over it, and PUT the merged shape back. Caller-supplied empty strings are treated as "do not change"; flip archival state through the dedicated `archived` boolean instead.

func (*Service) UpdateProjectEstimate

func (s *Service) UpdateProjectEstimate(ctx context.Context, args map[string]any) (ToolResult, error)

UpdateProjectEstimate handles clockify_projects_estimates_update: it updates a project's documented estimate fields.

func (*Service) UpdateProjectMemberships

func (s *Service) UpdateProjectMemberships(ctx context.Context, args map[string]any) (ToolResult, error)

UpdateProjectMemberships handles clockify_projects_memberships_update: it replaces a project's full membership array and optional user-group filter/rate metadata via PATCH.

func (*Service) UpdateProjectTemplate

func (s *Service) UpdateProjectTemplate(ctx context.Context, args map[string]any) (ToolResult, error)

UpdateProjectTemplate toggles a project's is_template flag via PATCH to the project template route.

func (*Service) UpdateProjectUserRate

func (s *Service) UpdateProjectUserRate(ctx context.Context, args map[string]any, endpoint string) (ToolResult, error)

UpdateProjectUserRate backs clockify_projects_rates_update: it sets a project member's rate at the given endpoint ("hourly-rate" or "cost-rate"). The change flows through every future time entry on the project.

func (*Service) UpdateTag

func (s *Service) UpdateTag(ctx context.Context, args map[string]any) (ToolResult, error)

UpdateTag performs a fetch-then-merge update of a tag. Clockify's PUT /workspaces/{ws}/tags/{id} is a full replacement; we GET the existing tag, layer caller changes on top, then PUT the merged shape back. The archived boolean can be toggled explicitly.

func (*Service) UpdateTask

func (s *Service) UpdateTask(ctx context.Context, args map[string]any) (ToolResult, error)

UpdateTask performs a fetch-then-merge update of a task. Clockify's PUT /projects/{pid}/tasks/{tid} is a full replacement; we GET the existing task, layer caller changes on top, then PUT the merged shape back. Empty-string caller args are treated as "no change".

func (*Service) UpdateTaskRate

func (s *Service) UpdateTaskRate(ctx context.Context, args map[string]any, endpoint string) (ToolResult, error)

UpdateTaskRate backs clockify_tasks_rates_update: it sets a task's rate at the given endpoint ("hourly-rate" or "cost-rate"), resolving project and task by id or name. The change affects the billable amount of every future entry on the task.

func (*Service) UpdateUserGroup

func (s *Service) UpdateUserGroup(ctx context.Context, args map[string]any) (ToolResult, error)

UpdateUserGroup updates a user group's name.

func (*Service) UpdateUserGroupAdmin

func (s *Service) UpdateUserGroupAdmin(ctx context.Context, args map[string]any) (ToolResult, error)

UpdateUserGroupAdmin handles clockify_groups_update: it updates a user group by ID. user_ids must carry the full desired membership, not a partial append.

func (*Service) UpdateUserRole

func (s *Service) UpdateUserRole(ctx context.Context, args map[string]any) (ToolResult, error)

UpdateUserRole updates a user's workspace role.

func (*Service) UpdateWebhook

func (s *Service) UpdateWebhook(ctx context.Context, args map[string]any) (ToolResult, error)

UpdateWebhook updates an existing webhook.

func (*Service) UsersInvite

func (s *Service) UsersInvite(ctx context.Context, args map[string]any) (ToolResult, error)

UsersInvite handles clockify_users_invite: it invites users by email. With send_email true this is a permission-changing external side effect; it supports a dry_run preview.

func (*Service) WeeklySummary

func (s *Service) WeeklySummary(ctx context.Context, args map[string]any) (ToolResult, error)

WeeklySummary handles clockify_reports_weekly: it runs Clockify's weekly report over a 7-day range.

type SummaryTotals

type SummaryTotals struct {
	Entries        int     `json:"entries"`
	RunningEntries int     `json:"runningEntries"`
	TotalSeconds   int64   `json:"totalSeconds"`
	TotalHours     float64 `json:"totalHours"`
}

SummaryTotals aggregates entry counts and tracked time across the containing DateRange. RunningEntries is the subset of Entries that are still in progress (no End yet); TotalSeconds is the canonical duration, TotalHours is the convenience float derived from it.

type TaskRateView

type TaskRateView struct {
	TaskID      string         `json:"task_id,omitempty"`
	TaskName    string         `json:"task_name,omitempty"`
	HourlyRate  *clockify.Rate `json:"hourly_rate,omitempty"`
	CostRate    *clockify.Rate `json:"cost_rate,omitempty"`
	HourlyMoney *MoneyView     `json:"hourly_money,omitempty"`
	CostMoney   *MoneyView     `json:"cost_money,omitempty"`
}

TaskRateView is the per-task rate projection within a ProjectRatesView: the task identity plus hourly/cost rates (raw and as MoneyView).

type TaskView

type TaskView struct {
	ID                     string                 `json:"id"`
	Name                   string                 `json:"name"`
	ProjectID              string                 `json:"projectId"`
	AssigneeID             string                 `json:"assigneeId,omitempty"`
	AssigneeIDs            []string               `json:"assigneeIds,omitempty"`
	Billable               bool                   `json:"billable"`
	BudgetEstimate         int64                  `json:"budgetEstimate,omitempty"`
	CostRate               *clockify.Rate         `json:"costRate,omitempty"`
	Duration               string                 `json:"duration,omitempty"`
	Estimate               string                 `json:"estimate,omitempty"`
	HourlyRate             *clockify.Rate         `json:"hourlyRate,omitempty"`
	Status                 string                 `json:"status,omitempty"`
	UserGroupIDs           []string               `json:"userGroupIds,omitempty"`
	CustomFieldsNormalized []CustomFieldValueView `json:"custom_fields_normalized,omitempty"`

	Rates            TaskRateView         `json:"rates"`
	Financials       ProjectFinancials    `json:"financials"`
	Estimates        ProjectEstimateView  `json:"estimates"`
	EstimateProgress EstimateProgressView `json:"estimate_progress"`
}

TaskView is the enriched task output embedded in a ProjectView (or returned by task tools): the core task fields plus normalized custom fields, rates, financials, estimates, and estimate progress.

type TimeEntryRef

type TimeEntryRef struct {
	ID          string `json:"id"`
	Description string `json:"description,omitempty"`
	ProjectID   string `json:"projectId,omitempty"`
	ProjectName string `json:"projectName,omitempty"`
	Start       string `json:"start,omitempty"`
	End         string `json:"end,omitempty"`
}

TimeEntryRef is a lightweight reference to a time entry (id, description, project, and time window) used in review and issue payloads.

type TimeEntryUpdatePreview

type TimeEntryUpdatePreview struct {
	Description     string   `json:"description"`
	ProjectID       string   `json:"project_id,omitempty"`
	TaskID          string   `json:"task_id,omitempty"`
	TagIDs          []string `json:"tag_ids,omitempty"`
	Start           string   `json:"start,omitempty"`
	End             string   `json:"end,omitempty"`
	Billable        bool     `json:"billable"`
	BillableState   string   `json:"billable_state,omitempty"`
	BillablePresent bool     `json:"billable_present,omitempty"`
}

TimeEntryUpdatePreview is the projected "current" shape of a time entry shown alongside a proposed-change diff during a dry-run update.

type TimeOffBalanceView

type TimeOffBalanceView map[string]any

TimeOffBalanceView is the pass-through time-off-balance projection: the raw upstream balance object as a generic map.

type TimeOffPolicyView

type TimeOffPolicyView map[string]any

TimeOffPolicyView is the pass-through time-off-policy projection: the raw upstream policy object as a generic map.

type TimeOffRequestView

type TimeOffRequestView map[string]any

TimeOffRequestView is the pass-through time-off-request projection: the raw upstream request object as a generic map.

type TimesheetIssue

type TimesheetIssue struct {
	Type            string   `json:"type"`
	Severity        string   `json:"severity"`
	Message         string   `json:"message"`
	EntryID         string   `json:"entryId,omitempty"`
	RelatedEntryIDs []string `json:"relatedEntryIds,omitempty"`
	Start           string   `json:"start,omitempty"`
	End             string   `json:"end,omitempty"`
}

TimesheetIssue is a single problem detected during a timesheet review (e.g. an overlap or gap): its type, severity, message, and the related entry IDs and time window.

type TimesheetReviewData

type TimesheetReviewData struct {
	Range            DateRange        `json:"range"`
	Totals           SummaryTotals    `json:"totals"`
	ByDay            []DaySummary     `json:"byDay"`
	ByProject        []ProjectSummary `json:"byProject"`
	Issues           []TimesheetIssue `json:"issues"`
	SuggestedActions []ToolSuggestion `json:"suggestedActions"`
	Entries          []EntryView      `json:"entries,omitempty"`
}

TimesheetReviewData is the shaped result of a timesheet review: the date range, totals, per-day and per-project breakdowns, detected issues, suggested actions, and the underlying entries.

type ToolError

type ToolError struct {
	OK        bool              `json:"ok"`
	Supported *bool             `json:"supported,omitempty"`
	Performed *bool             `json:"performed,omitempty"`
	Action    string            `json:"action"`
	IDs       map[string]string `json:"ids,omitempty"`
	Error     ErrorInfo         `json:"error"`
	Recovery  RecoveryHint      `json:"recovery"`
	Warnings  []Warning         `json:"warnings,omitempty"`
}

ToolError is the recoverable-failure envelope a tool handler returns (ok:false): the action, any partial IDs, a structured Error, and a RecoveryHint guiding the caller toward a fix. Supported/Performed flag the "unsupported endpoint" and "no-op" cases.

type ToolResult

type ToolResult struct {
	OK       bool              `json:"ok"`
	Action   string            `json:"action"`
	Entity   string            `json:"entity,omitempty"`
	IDs      map[string]string `json:"ids,omitempty"`
	Data     any               `json:"data,omitempty"`
	Meta     map[string]any    `json:"meta,omitempty"`
	Changed  ChangeSet         `json:"changed,omitzero"`
	Warnings []Warning         `json:"warnings,omitempty"`
	Next     []NextAction      `json:"next,omitempty"`
}

ToolResult is the single success envelope every tool handler returns. Post-T2.1 the legacy ResultEnvelope name was retired and ToolResult is now the only success type. OK is the boolean success flag; Action mirrors the tool name for client-side dispatch; Data carries the typed payload; Meta carries cross-cutting metadata (pagination cursors, fingerprint hashes). Entity / IDs / Changed / Warnings / Next are optional — every field uses omitempty (and Changed uses omitzero for value-type omission), so a narrow handler that fills only {OK, Action, Data, Meta} emits the historical four-key wire shape unchanged.

type ToolSuggestion

type ToolSuggestion struct {
	Tool        string         `json:"tool"`
	Reason      string         `json:"reason"`
	Arguments   map[string]any `json:"arguments,omitempty"`
	MissingArgs []string       `json:"missingArgs,omitempty"`
}

ToolSuggestion recommends a follow-up tool call: the tool name, the reason, proposed arguments, and any arguments the caller still needs to supply.

type UnbilledForClientView

type UnbilledForClientView struct {
	ClientID         string              `json:"client_id,omitempty"`
	Client           string              `json:"client,omitempty"`
	Range            FinancialRangeView  `json:"range"`
	Entries          []ReportEntryView   `json:"entries,omitempty"`
	EntrySummary     ReportEntrySummary  `json:"entry_summary"`
	Totals           ReportTotalsSummary `json:"totals_summary"`
	Financials       EntryFinancials     `json:"financials"`
	SuggestedActions []ToolSuggestion    `json:"suggestedActions,omitempty"`
	Warnings         []string            `json:"warnings,omitempty"`
	Raw              map[string]any      `json:"raw,omitempty"`
}

UnbilledForClientView is the shaped output of the unbilled-work composite: a client's unbilled entries over a date range with entry/totals summaries, financials, and suggested next actions.

type UserFeatureFlags

type UserFeatureFlags struct {
	Scheduling bool `json:"scheduling,omitempty"`
	Approval   bool `json:"approval,omitempty"`
	PTO        bool `json:"pto,omitempty"`
}

UserFeatureFlags reports which optional Clockify features (scheduling, approval, PTO) are available to the current user.

type UserView

type UserView struct {
	ID                     string                 `json:"id"`
	Name                   string                 `json:"name"`
	Email                  string                 `json:"email"`
	ActiveWorkspace        string                 `json:"activeWorkspace,omitempty"`
	CustomFields           any                    `json:"customFields,omitempty"`
	CustomFieldsNormalized []CustomFieldValueView `json:"custom_fields_normalized,omitempty"`
	DefaultWorkspace       string                 `json:"defaultWorkspace,omitempty"`
	Memberships            any                    `json:"memberships,omitempty"`
	ProfilePicture         string                 `json:"profilePicture,omitempty"`
	Settings               any                    `json:"settings,omitempty"`
	Status                 string                 `json:"status,omitempty"`
	ReportDefaults         ReportDefaults         `json:"report_defaults"`
	FeatureFlags           UserFeatureFlags       `json:"feature_flags"`
}

UserView preserves the upstream user fields while adding compact settings blocks that agents can use for report defaults and feature-aware wording.

type ValidationProblem

type ValidationProblem struct {
	Code        string   `json:"code,omitempty"`
	Field       string   `json:"field,omitempty"`
	Message     string   `json:"message"`
	Remediation string   `json:"remediation,omitempty"`
	Refs        []string `json:"refs,omitempty"`
}

ValidationProblem is a single validation error or warning: a code, the offending field, a message, and an optional remediation hint with refs.

type ValidationView

type ValidationView struct {
	Status         string              `json:"status"`
	OK             *bool               `json:"ok,omitempty"`
	Errors         []ValidationProblem `json:"errors,omitempty"`
	Warnings       []ValidationProblem `json:"warnings,omitempty"`
	PreviewQuality string              `json:"preview_quality,omitempty"`
}

ValidationView is the validation block attached to a dry-run preview: the overall status/ok, any errors and warnings, and a preview-quality label.

type Warning

type Warning struct {
	Code    string `json:"code,omitempty"`
	Message string `json:"message"`
}

Warning is a non-fatal advisory attached to a tool result: an optional code and a human-readable message.

type WebhookLogView

type WebhookLogView map[string]any

WebhookLogView is the pass-through projection of a webhook delivery-log entry as a generic map.

type WeeklyDayTotalView

type WeeklyDayTotalView struct {
	Date            string                `json:"date,omitempty"`
	IsFuture        bool                  `json:"is_future,omitempty"`
	Duration        EntryDurationView     `json:"duration"`
	Financials      EntryFinancials       `json:"financials"`
	MoneyByCurrency []MoneyByCurrencyView `json:"money_by_currency,omitempty"`
}

WeeklyDayTotalView is the per-day total within a weekly report: the date (with a future-day flag), duration, financials, and per-currency money.

type WeeklySummaryData

type WeeklySummaryData struct {
	Range            DateRange            `json:"range"`
	Totals           SummaryTotals        `json:"totals"`
	ByDay            []DaySummary         `json:"byDay"`
	ByProject        []ProjectSummary     `json:"byProject"`
	SuggestedActions []ToolSuggestion     `json:"suggestedActions"`
	Entries          []clockify.TimeEntry `json:"entries,omitempty"`
	UnassignedKey    string               `json:"unassignedKey,omitempty"`
}

WeeklySummaryData is the structured payload for clockify_weekly_ summary: a date range, total counts, per-day and per-project rollups, suggested follow-up actions for the agent, and (optionally) the raw entries so callers can drill into specific records without a second round-trip.

type WorkspaceSettings

type WorkspaceSettings struct {
	Currencies                any      `json:"currencies,omitempty"`
	FeaturePlan               string   `json:"feature_plan,omitempty"`
	SubscriptionLabel         string   `json:"subscription_label,omitempty"`
	PlanCohort                string   `json:"plan_cohort,omitempty"`
	DurationFormat            string   `json:"duration_format,omitempty"`
	CurrencyFormat            any      `json:"currency_format,omitempty"`
	NumberFormat              any      `json:"number_format,omitempty"`
	ProjectLabel              string   `json:"project_label,omitempty"`
	TaskLabel                 string   `json:"task_label,omitempty"`
	WorkingDays               []string `json:"working_days,omitempty"`
	WorkingDayPattern         string   `json:"working_day_pattern,omitempty"`
	WeekendIncluded           bool     `json:"weekend_included,omitempty"`
	WorkingDayCount           int      `json:"working_day_count,omitempty"`
	LockPolicy                any      `json:"lock_policy,omitempty"`
	Rounding                  any      `json:"rounding,omitempty"`
	EntityCreationPermissions any      `json:"entity_creation_permissions,omitempty"`
	HasHourlyRate             bool     `json:"has_hourly_rate,omitempty"`
	HasCostRate               bool     `json:"has_cost_rate,omitempty"`
	MembershipsCount          int      `json:"memberships_count,omitempty"`
	Source                    string   `json:"source,omitempty"`
}

WorkspaceSettings is the summarized workspace settings projection: plan, formats, working-day configuration, lock/rounding policy, rate availability, and membership count.

type WorkspaceView

type WorkspaceView struct {
	ID                      string            `json:"id"`
	Name                    string            `json:"name"`
	CakeOrganizationID      string            `json:"cakeOrganizationId,omitempty"`
	CostRate                *clockify.Rate    `json:"costRate,omitempty"`
	Currencies              any               `json:"currencies,omitempty"`
	FeatureSubscriptionType string            `json:"featureSubscriptionType,omitempty"`
	Features                []string          `json:"features,omitempty"`
	FeaturesHuman           []FeatureLabel    `json:"features_human,omitempty"`
	SubscriptionLabel       string            `json:"subscription_label,omitempty"`
	PlanCohort              string            `json:"plan_cohort,omitempty"`
	HourlyRate              *clockify.Rate    `json:"hourlyRate,omitempty"`
	ImageURL                string            `json:"imageUrl,omitempty"`
	Memberships             any               `json:"memberships,omitempty"`
	Subdomain               any               `json:"subdomain,omitempty"`
	WorkspaceSettings       any               `json:"workspaceSettings,omitempty"`
	SettingsSummary         WorkspaceSettings `json:"settings_summary"`
}

WorkspaceView is the enriched workspace output: the core workspace fields plus human-readable feature labels, a subscription/plan summary, and a settings summary.

Source Files

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL