Project Tools
create_project
Create a new project. Owner only.
Writes to: 02. Projects
Parameters:
| Param | Required | Description |
|---|---|---|
requesting_user_slack_id | ✅ | |
project_name | ✅ | Unique project name |
project_type | ✅ | "Retainer" | "T&M" | "Fixed Price" | "Pro Bono" | "Agile" | "Internal" — never defaulted |
client_name | Cond. | Client org — created automatically if new. Omit for Internal projects — VERA assigns the implicit "Internal" client automatically |
contract_value | Cond. | Required for Fixed Price |
hours_budget | Cond. | Required for Retainer (annual hours). Optional for others. |
billing_rate | Hourly rate billed to client | |
deadline | YYYY-MM-DD | |
notes | ||
project_category | Defaults to "client" |
Rules:
- Never assume a default project type — always ask
client_nameis not required for Internal projects — the Internal client is implicit- Fixed Price requires a positive
contract_value— the endpoint rejects creation with❌ contract_value is required for Fixed Price projectsif it's missing or ≤ 0. Fixed Price revenue is% complete × contract_value, so without it the project would recognise $0 revenue forever. - For Agile parents: no contract_value or hours_budget on the parent itself
- After Agile parent creation, offer to set up Sprint 1
- "Create a retainer" means
create_projectwithproject_type="Retainer"— this tool creates the parent engagement. The first period child is auto-created bycreate_project. Usecreate_retainer_periodonly when adding a new period to an existing retainer parent (e.g. "create the June period for Acme Retainer"). - On creation, the Project Management task is automatically enabled on the new project so it starts with at least one enabled task — you can allocate hours immediately, and use Edit tasks to add more (Design, Development, etc.). If the tenant has archived or renamed its Project Management task, the project is simply created with no default task (no error).
rename_project
Rename a project and update all references. Owner only.
Updates: 02. Projects, 01. Time Entries
Parameters:
| Param | Required | Description |
|---|---|---|
requesting_user_slack_id | ✅ | |
old_name | ✅ | |
new_name | ✅ |
Protected projects: the internal time-off projects PTO, Sick, and Leave can be neither renamed nor cancelled (cancel_project carries the same guard) — both return a 403 ("…is a protected time-off project and cannot be renamed/cancelled") to keep time-off logging intact. Other internal/overhead projects are unaffected.
update_project
Update one or more fields on an existing project. Owner or Manager.
Updates: 02. Projects
Parameters:
| Param | Required | Description |
|---|---|---|
requesting_user_slack_id | ✅ | |
project_name | ✅ | Current project name |
new_name | Rename the project | |
status | active | completed | cancelled | |
is_billable | Boolean | |
alert_threshold | % at which to flag the budget (default 80) | |
notes | Free-text notes | |
deadline | YYYY-MM-DD | |
contract_value | Owner only. Setting this as a Manager returns ❌ Failed: Only owners can change a project's contract_value… | |
billing_rate | Owner only. Same gate as contract_value. | |
hours_budget | Owner only. Same gate as contract_value. |
Role notes:
- Managers can set
new_name,status,is_billable,alert_threshold,notes, anddeadline. contract_value,billing_rate, andhours_budgetare owner-only on write, mirroring the read-side isolation inget_project_info. A manager attempting to set any of these gets a 403.
Deterministic routing (updated #1090): Field-bearing phrasings now route to update_project in the extractor instead of being hijacked by edit_entry or set_rate. The extractor has an update_project entry with object_nouns: ['contract value', 'billing rate', 'status', 'notes', 'billable', 'is billable'].
Deterministic owner execution (updated #1091): contract_value, billing_rate, and hours_budget now execute via DET confirm→fire gates (no model turn). Both colon form ("update CityCore App Development: contract value 130000") and preposition form ("set the contract value for CityCore App Development to 130000") resolve the project and present a clean confirm. Owner-only denial is also deterministic. Missing-value inputs fall through to the model.
list_projects
List all projects (filtered by role).
Reads from: 02. Projects, 04. Clients, 03. Users
Returns: name, client, type, pm_name, status, deadline (Owner/Manager only)
get_project_info
Full project details. Always call this first when checking project status — it tells you the type, which determines whether to follow up with get_project_status or get_retainer_status.
Reads from: 02. Projects, 04. Clients, 03. Users
Returns: name, client, type, budget_hours, status, pm_name, deadline (Owner/Manager), contract_value (Owner), billing_rate (Owner)
get_project_status
Task-level budget status for non-retainer projects.
Reads from: 01. Time Entries, 06. Project_Tasks, 02. Projects
Returns per task: hours_logged, budget_hours, % used, alert status, committed hours (logged + allocated)
Do not use for retainers — use get_retainer_status instead.
get_project_health
Burn rate health for retainer projects, with envelope-aware forecast.
Reads from: 01. Time Entries, 02. Projects, 07. Budgets
Returns: hours_logged, days_elapsed, pace_per_day, projected_eom_hours, allocated_remaining, forecast_with_allocations, variance, utilisation%, status
Status values: critical_overpace, warning_overpace, on_track, warning_underpace, critical_underpace
get_my_projects
Projects where the requesting user is the PM (or all projects if Owner).
Parameters: requesting_user_slack_id
delete_project
Permanently hard-delete a project. Owner only. Only allowed when the project is completely empty: no time entries, no allocation envelopes (any status), no vendor liabilities, and no period/sprint children. Use cancel_project for anything with history.
Writes to: 02. Projects
Parameters:
| Param | Required | Description |
|---|---|---|
requesting_user_slack_id | ✅ | |
project_name | Name of the project | |
project_id | ID of the project (alternative to name) |
Returns 400 if the project has time entries, budgets (any status), liabilities, or child periods/sprints — with a message pointing to
cancel_projectas the correct affordance. The protected time-off projects (PTO, Sick, Leave) return 403. This action is irreversible.
Returns: project_id, name, message
set_project_budget
Set the project-level hours budget (Tier 1). Owner only.
Updates: 02. Projects col D
Parameters:
| Param | Required | Description |
|---|---|---|
requesting_user_slack_id | ✅ | |
project_name | ✅ | |
budget_hours | ✅ | Total hours cap |
set_project_deadline
Set the project delivery date. Owner or PM of the project (Managers who are not the PM get a deterministic denial).
Updates: 02. Projects
Parameters:
| Param | Required | Description |
|---|---|---|
requesting_user_slack_id | ✅ | |
project_name | ✅ | |
deadline | ✅ | YYYY-MM-DD |
Deterministic routing: natural-language date inputs ("set the deadline for X to next Friday") resolve the date and show a confirm with the concrete ISO date before writing — no model round-trip. A non-PM manager gets a deterministic denial: ❌ Failed: Only owners or <project>'s PM can set its deadline. ISO date inputs ("set the deadline for X to 2027-01-16") fall through to the model.
list_tasks
All task types with billability flag.
Reads from: 05. Tasks
create_task
Create a new global task type. Owner only.
Writes to: 05. Tasks
Parameters: requesting_user_slack_id, task_name, is_billable (true/false)
rename_task
Rename a task type globally. Owner only.
Updates: 05. Tasks
Parameters: requesting_user_slack_id, old_name, new_name
archive_task
Archive a task type so it no longer appears in menus or as a write target. Owner only. Historical time entries are preserved. Use unarchive_task to restore.
Writes to: 05. Tasks
Parameters: requesting_user_slack_id, task_name
Hard fails (409) if the task is enabled on any active project — disable it from those projects first.
Returns: task_id, task_name
unarchive_task
Restore an archived task so it appears in menus again. Owner only.
Writes to: 05. Tasks
Parameters: requesting_user_slack_id, task_name
Returns: task_id, task_name
get_project_tasks
All enabled tasks for a project, with budget and hours logged.
Reads from: 06. Project_Tasks, 05. Tasks, 01. Time Entries
Returns per task: task_name, is_billable, budget_hours, alert_threshold, hours_logged, % used, budget_summary
budget_summary includes:
tasks_without_budget: count of enabled tasks with no budget setover_project_budget: whether task totals exceed the project budgetunallocated_hours: project budget minus sum of task budgets
enable_task_for_project
Enable a task on a project with optional budget. Owner or project PM.
Writes to: 06. Project_Tasks
Parameters:
| Param | Required | Description |
|---|---|---|
requesting_user_slack_id | ✅ | |
project_name | ✅ | |
task_name | ✅ | |
budget_hours | Optional hours budget for this task | |
alert_threshold | Percent — defaults to 80 |
disable_task_for_project
Disable a task on a project (deletes the row from 06. Project_Tasks). Owner or project PM.
Parameters: requesting_user_slack_id, project_name, task_name
get_retainer_status
Monthly burn rate for a retainer project. See Retainers for interpretation guide.
Reads from: 01. Time Entries, 02. Projects, 07. Budgets
Parameters: requesting_user_slack_id, project_name
Returns: budget_hours, hours_logged, hours_remaining, days_elapsed, days_remaining, pace_per_day, projected_eom_hours, allocated_remaining, forecast_with_allocations, variance, utilisation_percent, exceed_date, unused_hours, unused_value, status
get_pm_retainer_summary
All retainer projects assigned to a PM, with burn status for each. Manager/Owner.
create_sprint
Create a new sprint under an Agile parent. Owner only.
Writes to: 02. Projects
Parameters:
| Param | Required | Description |
|---|---|---|
requesting_user_slack_id | ✅ | |
parent_project_name | ✅ | The Agile parent project |
contract_value | ✅ | Must be asked explicitly — never derived |
hours_budget | ✅ | Sprint hours estimate |
Sprint number is auto-incremented — do not specify manually.
get_agile_summary
All sprints under an Agile project with revenue recognition.
Reads from: 02. Projects, 01. Time Entries
Returns per sprint: sprint_name, sprint_number, status, contract_value (Owner), hours_budget, hours_logged, recognised_revenue (Owner)
update_sprint_status
Transition a sprint from planned to active. Owner only. No confirmation prompt needed.
Updates: 02. Projects col L
Parameters: requesting_user_slack_id, sprint_id, new_status ("active")