Envelope Tools
All envelope tools require Manager or Owner role unless noted. See Envelopes for conceptual background.
allocate_hours
Create a per-person hour envelope on a project.
Writes to: 07. Budgets
Parameters:
| Param | Required | Description |
|---|---|---|
requesting_user_slack_id | ✅ | |
project_name | ✅ | |
user_name or user_slack_id | ✅ | Person receiving the envelope |
allocated_hours | ✅ | Hours for this envelope |
task_id or task_name | ✅ | Work-category tag — must be enabled for the project |
Task constraint: The task must be enabled for the target project (via Edit tasks / enable_task_for_project). A project with no enabled tasks cannot receive any envelope. A task that is globally active but not enabled for the project is rejected with a 400 error listing which tasks are enabled.
Returns: envelope id (use for updates/cancellations), and overbooked: true if the person is over capacity.
If overbooked: true is returned, always surface the warning: "⚠️ [Name] is overbooked by Xh."
Both word orders accepted: allocate 20h to Apex for Rachel as Design (natural: to <project> for <person>) and allocate 20h to Rachel on Apex for Design (legacy: to <person> on <project>) resolve identically. VERA binds each name to the slot matching what it actually is — no re-asking when all slots are present.
update_allocation
Change the hours or task on an existing envelope.
Updates: 07. Budgets col D (hours), col I (task)
Parameters:
| Param | Required | Description |
|---|---|---|
requesting_user_slack_id | ✅ | |
allocation_id | ✅ | The envelope's ID |
new_allocated_hours | New hours value | |
new_task_id or new_task_name | New task category |
To find the envelope ID, call get_allocations or get_person_allocation_summary first.
Restrictions: Cannot target a Retainer or Agile parent project — envelopes must reference the active period or sprint child. The error message names the active period to guide the user.
Audit: The audit message shows exactly what changed (e.g. "40h → 50h" or "task: Design → Development").
Deterministic routing (M-ENV-U): Natural language like "update Sarah's envelope on Acme to 50h" resolves the target envelope directly from the entity pipeline. If the envelope resolves unambiguously and new hours are present, VERA shows a before→after confirm gate ("Change … (40h) to 50h? Reply 1 to confirm.") — no model round-trip. If the user holds two envelopes on the same project (e.g. Design + Development), VERA shows a numbered disambiguation menu; the model never picks the candidate.
cancel_allocation
Mark an envelope as cancelled. The record is kept for audit purposes. Cancellation is terminal — VERA does not track lineage between a cancelled envelope and any replacement.
Updates: 07. Budgets col F (status → "cancelled")
Parameters: requesting_user_slack_id, allocation_id
Deterministic routing (M-ENV-D): Natural language like "cancel Sarah's envelope on Acme" resolves and always shows a terminal confirm gate ("Cancel … ? This is terminal — reply 1 to confirm.") before executing. Ambiguous → disambiguation menu. The model never cancels without explicit user confirmation.
reactivate_allocation
Restore a cancelled envelope to active. Use when an envelope was cancelled by mistake.
Updates: 07. Budgets col F (status → "active")
Parameters: requesting_user_slack_id, allocation_id
No uniqueness check is performed — multiple active envelopes for the same user/project/task are allowed.
Audit: ♻️
Deterministic routing (M-ENV-D undo): Natural language like "reactivate Sarah's envelope on Acme" fires instantly when the cancelled envelope resolves unambiguously — no confirm gate (non-destructive). Ambiguous → disambiguation menu; the digit fires the reactivation directly. No model invocation.
get_allocations
List envelopes with optional filters.
Reads from: 07. Budgets, 03. Users, 02. Projects, 05. Tasks
Parameters:
| Param | Description |
|---|---|
requesting_user_slack_id | |
user_id | Filter by person |
project_id | Filter by project |
status | "active" (default) or "cancelled" |
include_usage | "true" to add usage enrichment (see below). Default omits it. |
Returns: Each allocation includes user_name, project_name, and task_name (the resolved task label, or null if no task is tagged).
When include_usage=true, envelopes are bucketed by (user_id, project_id, task_id) before enrichment. Multiple envelopes sharing the same triple collapse into one bucket row; allocated_hours is summed and time entries are attributed once — no double-counting. Each bucket row includes:
| Field | Description |
|---|---|
allocation_id | The single envelope's id if the bucket has exactly one envelope; null for multi-envelope buckets |
envelope_ids | Array of all envelope IDs in this bucket |
envelopes | Array of constituent envelope objects { allocation_id, allocated_hours } — used for per-envelope Edit/Cancel modals |
display_project_id / display_project_name | The parent project for retainer/agile period children, otherwise the project itself |
project_deadline | The period's period_end, or the project's deadline, or the parent's deadline |
hours_logged | Hours attributed to this bucket (partitioned, not duplicated across buckets) |
budget_remaining | allocated_hours − hours_logged (not floored — negative values are meaningful) |
pct_used | round(hours_logged / allocated_hours × 100), or null if allocated_hours is 0 and hours have been logged |
project_status | The status (active, cancelled, completed, etc.) of the display project (parent for retainer/agile periods, otherwise the project itself) |
Used by the web console's top-level Envelopes overview (/console/envelopes).
get_my_allocations
The requesting user's active envelopes.
Parameters: requesting_user_slack_id
get_my_assignments
"What should I work on?" — returns active envelopes for the requesting user with remaining hours.
This is the primary tool for Users to understand their current workload. It shows:
- Projects they're allocated to
- Hours allocated vs. hours logged
- Hours remaining in each envelope
Parameters: requesting_user_slack_id
Any active user. Assignment = having an active envelope. Anyone can log time to any project regardless of assignment — envelopes are a planning tool, not a gate.
get_project_assignments
Who is allocated to a project. Manager/Owner.
Reads from: 07. Budgets, 03. Users
Returns: user_id, user_name, allocated_hours, hours_logged, hours_remaining, task_id (if tagged), status
Permission: Owners see all. Managers see only their assigned projects.
get_person_allocation_summary
All envelopes for one person across all their projects.
Reads from: 07. Budgets, 02. Projects
Parameters: requesting_user_slack_id, user_name
Returns per envelope: project_name, allocated_hours, hours_logged, hours_remaining, status, overdraw flag
get_project_allocation_summary
All envelopes for one project, bucketed by (user_id, project_id, task_id).
Reads from: 07. Budgets, 03. Users, 01. Time Entries, 05. Tasks
Parameters: requesting_user_slack_id, project_name
Multiple envelopes for the same person+task collapse into one row (see bucket model above). hours_logged is attributed once per entry — no double-counting when a person has two envelopes on the same task.
get_team_availability
Remaining hours per person across all active envelopes.
Reads from: 07. Budgets, 01. Time Entries, 03. Users
Returns per person: available_hours, allocated_hours, remaining_hours, overbooked flag
Use this for a quick capacity snapshot before adding new work.
get_estimates_vs_actuals
Compare allocated hours (the plan) against logged hours (the actuals).
Reads from: 07. Budgets, 01. Time Entries
Parameters:
| Param | Description |
|---|---|
requesting_user_slack_id | |
week_start | "this week", "last week", or YYYY-MM-DD |
user_name | Optional — filter to one person |
project_name | Optional — filter to one project |
Returns: per person/project: allocated_hours, actual_hours, delta
delta > 0= over plan (more hours worked than allocated)delta < 0= under plan (fewer hours than allocated)
Surface meaningful divergences (delta ≥ ±20%) as insights. Never show estimates vs actuals for future weeks — redirect to get_allocations instead.
check_capacity
Can the team absorb new work? Takes discipline requirements and a timeline.
Parameters:
| Param | Description |
|---|---|
requesting_user_slack_id | |
discipline_requirements | Array of {discipline, hours_needed} |
start_date | YYYY-MM-DD |
end_date | YYYY-MM-DD |
Returns per discipline:
fte_sufficient: FTE has headroom — names and available hoursfte_partial: FTE bench partially covers — gap amountcontractor_required: No FTE capacity — hours of contractor coverage needed- Contractor conflicts flagged if any contractors are double-booked
get_capacity_forecast
N-week rolling capacity outlook.
Parameters:
| Param | Description |
|---|---|
requesting_user_slack_id | |
weeks | Number of weeks to forecast (default 4, max 12) |
Returns per week:
- week_start, utilisation_percent, unallocated_hours
- uncovered_projects: projects with no one allocated that week
- overbooked users: name + hours over
Interpretation:
- < 70% utilisation → plenty of headroom
- 70–90% → healthy
90% → nearly full, be careful
- uncovered_projects → flag immediately — no coverage that week