opbox

The time.* family (4 verbs). Every verb enters through the one front door: it is capability-checked, permission-checked, scope-checked and audited before it runs (see Security & permissions). Each entry below lists its capability, risk class (which fixes the minimum autonomy level), the minimum caller permission, its availability tier, whether it is idempotent, and any outbound egress.

Edittime.edit

PropertyValue
Capabilitymatter.write
Risk classWrite - autonomy L1
Min. permissionMember
AvailabilityCore - always on (MCP tier 1)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

Amend an UNBILLED entry. { id, minutes?, description?, workDate?, billable?, rateMinor? }. A billed entry (billed_line_item_id set, or locked) is REFUSED - once time has been rolled into an invoice line it is immutable (the WHERE clause enforces it; a zero-row update is reported as a clean reject, never a silent no-op).

Input

FieldTypeRequiredDescription
idstringyesthe time_entry id
minutesintegerno
descriptionstringno
workDatestringno
billablebooleanno
rateMinorintegerno

Call POST /v/time.edit with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool time.edit.

Listtime.list

PropertyValue
Capabilitymatter.read
Risk classRead - autonomy L0
Min. permissionMember
AvailabilityCore - always on (MCP tier 1)
IdempotentYes
EgressNone - in-box (pure Postgres, no outbound call)
Render schemaYes - drives an inline chat artefact and a GUI panel

A matter’s time entries. { matterId, unbilledOnly?, from?, to? }. Returns the rows (newest-work-first) plus integer minute totals (all / billable) for the slice.

Input

FieldTypeRequiredDescription
matterIdstringyes
unbilledOnlybooleanno
fromstringnoYYYY-MM-DD
tostringnoYYYY-MM-DD

Call POST /v/time.list with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool time.list.

Logtime.log

PropertyValue
Capabilitymatter.write
Risk classWrite - autonomy L1
Min. permissionMember
AvailabilityCore - always on (MCP tier 1)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

Record a unit of time on a matter. { matterId, minutes, description?, workDate?(YYYY-MM-DD), billable?(=true), stepId?, actorId?, rateMinor? }. The timekeeper defaults to the caller (actorId overrides, e.g. an admin logging on someone’s behalf); created_by is always the caller. rateMinor is an optional per-entry rate override (NULL = the matter profile rate at roll-up).

Input

FieldTypeRequiredDescription
matterIdstringyes
minutesintegeryesduration in whole minutes (>0)
descriptionstringno
workDatestringnoYYYY-MM-DD (default today)
billablebooleannodefault true
stepIdstringnooptional matter step
actorIdstringnotimekeeper; default the caller
rateMinorintegernooptional per-entry rate override, minor-units/hour

Call POST /v/time.log with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool time.log.

Rolluptime.rollup

PropertyValue
Capabilitymatter.write
Risk classWrite - autonomy L1
Min. permissionAdmin
AvailabilityVertical (MCP tier 3)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

Roll a matter’s UNBILLED BILLABLE time for a period into delivered matter_line_item rows + a timesheet. { matterId, periodStart, periodEnd, taxRateBp? }. The existing bill.invoice then mints the invoice from the delivered lines (this verb moves no money). v1 prices at the matter rateMinor override; resolving the PRODUCTS rate-card price + per-entry overrides is the next refinement (the rate-card provenance is already carried onto each line).

Input

FieldTypeRequiredDescription
matterIdstringyes
periodStartstringyesYYYY-MM-DD
periodEndstringyesYYYY-MM-DD
taxRateBpintegernotax rate in basis points (default 0)

Call POST /v/time.rollup with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool time.rollup.