New Expensify integrates task management directly into chat, allowing you to create actionable items from discussions, assign them to team members, and track progress—all without leaving the conversation.
What Are Tasks?
Tasks in New Expensify are actionable items that:
Have a clear title and optional description
Can be assigned to specific team members
Are linked to a parent chat or report thread
Track completion status
Send notifications to assignees
Generate chat messages in relevant conversations
Every task is actually a special type of report with its own chat thread. This means you can discuss task details in a dedicated space.
Creating Tasks
From Chat
Create a task directly from any conversation:
Open the Chat
Navigate to the 1-on-1, group chat, or report thread where you want to create a task.
Create Task
Click the + button and select Assign Task , or use the /task command.
Fill Details
Title : Clear, actionable task description
Assignee : Who will complete the task
Description : Optional details or context
Submit
Click Create Task . The task appears in both the current chat and the assignee’s chat.
Task Creation Code
Here’s how tasks are created programmatically:
// From src/libs/actions/Task.ts
type CreateTaskAndNavigateParams = {
parentReport : OnyxEntry < OnyxTypes . Report >;
title : string ;
description : string ;
assigneeEmail : string ;
currentUserAccountID : number ;
currentUserEmail : string ;
assigneeAccountID ?: number ;
assigneeChatReport ?: OnyxEntry < OnyxTypes . Report >;
policyID ?: string ;
};
function createTaskAndNavigate ( params : CreateTaskAndNavigateParams ) {
const {
parentReport ,
title ,
description ,
assigneeEmail ,
currentUserAccountID ,
assigneeAccountID = 0 ,
assigneeChatReport ,
policyID = CONST . POLICY . OWNER_EMAIL_FAKE ,
} = params ;
const parentReportID = parentReport ?. reportID ;
if ( ! parentReportID ) {
return ;
}
// Build optimistic task report
const optimisticTaskReport = ReportUtils . buildOptimisticTaskReport (
currentUserAccountID ,
parentReportID ,
assigneeAccountID ,
title ,
description ,
policyID
);
// Create task action in parent report
const optimisticTaskCreatedAction = ReportUtils . buildOptimisticCreatedReportAction (
currentUserEmail
);
const optimisticAddCommentReport = ReportUtils . buildOptimisticTaskCommentReportAction (
taskReportID ,
title ,
assigneeAccountID ,
`task for ${ title } ` ,
parentReportID
);
// Optimistic Onyx updates
const optimisticData = [
{
onyxMethod: Onyx . METHOD . SET ,
key: ` ${ ONYXKEYS . COLLECTION . REPORT }${ optimisticTaskReport . reportID } ` ,
value: completeOptimisticTaskReport ,
},
{
onyxMethod: Onyx . METHOD . SET ,
key: ` ${ ONYXKEYS . COLLECTION . REPORT_ACTIONS }${ optimisticTaskReport . reportID } ` ,
value: {
[optimisticTaskCreatedAction.reportActionID]: optimisticTaskCreatedAction ,
},
},
{
onyxMethod: Onyx . METHOD . MERGE ,
key: ` ${ ONYXKEYS . COLLECTION . REPORT }${ parentReportID } ` ,
value: {
lastMessageText: `task for ${ title } ` ,
hasOutstandingChildTask: assigneeAccountID === currentUserAccountID ,
},
},
];
API . write ( WRITE_COMMANDS . CREATE_TASK , parameters , {
optimisticData ,
successData ,
failureData ,
});
playSound ( SOUNDS . DONE );
notifyNewAction ( parentReportID , optimisticAddCommentReport . reportAction , true );
}
When you create a task, New Expensify automatically creates:
The task report itself
A comment in the parent chat
A message in the assignee’s chat (if different from creator)
All associated Onyx state updates for offline-first functionality
Managing Tasks
Completing Tasks
Mark tasks as complete when finished:
Open Task
Click on the task from your task list or from the chat where it was created.
Mark Complete
Click the Complete button or check the checkbox.
Confirmation
The task is marked complete and all participants are notified.
// Complete task implementation from src/libs/actions/Task.ts
function completeTask (
taskReport : OnyxEntry < OnyxTypes . Report >,
hasOutstandingChildTaskInParentReport : boolean ,
hasOutstandingChildTask : boolean ,
parentReportAction : OnyxEntry < ReportAction > | undefined ,
) : OnyxData {
const taskReportID = taskReport ?. reportID ;
if ( ! taskReportID ) {
return {};
}
const message = `marked as complete` ;
const completedTaskReportAction = ReportUtils . buildOptimisticTaskReportAction (
taskReportID ,
CONST . REPORT . ACTIONS . TYPE . TASK_COMPLETED ,
message
);
const optimisticData = [
{
onyxMethod: Onyx . METHOD . MERGE ,
key: ` ${ ONYXKEYS . COLLECTION . REPORT }${ taskReportID } ` ,
value: {
stateNum: CONST . REPORT . STATE_NUM . APPROVED ,
statusNum: CONST . REPORT . STATUS_NUM . APPROVED ,
lastReadTime: DateUtils . getDBTime (),
},
},
{
onyxMethod: Onyx . METHOD . MERGE ,
key: ` ${ ONYXKEYS . COLLECTION . REPORT_ACTIONS }${ taskReportID } ` ,
value: {
[completedTaskReportAction.reportActionID]: completedTaskReportAction ,
},
},
];
// Update parent report to reflect task completion
if ( hasOutstandingChildTaskInParentReport ) {
optimisticData . push ({
onyxMethod: Onyx . METHOD . MERGE ,
key: ` ${ ONYXKEYS . COLLECTION . REPORT }${ taskReport ?. parentReportID } ` ,
value: {
hasOutstandingChildTask ,
},
});
}
playSound ( SOUNDS . SUCCESS );
API . write ( WRITE_COMMANDS . COMPLETE_TASK , parameters , {
optimisticData ,
successData ,
failureData ,
});
return { optimisticData , successData , failureData };
}
Reopening Tasks
Reopen a completed task if more work is needed:
// Reopen task from src/libs/actions/Task.ts
function reopenTask (
taskReport : OnyxEntry < OnyxTypes . Report >,
parentReport : OnyxEntry < OnyxTypes . Report >,
currentUserAccountID : number ,
) {
const taskReportID = taskReport ?. reportID ;
if ( ! taskReportID ) {
return ;
}
const message = `marked as incomplete` ;
const reopenedTaskReportAction = ReportUtils . buildOptimisticTaskReportAction (
taskReportID ,
CONST . REPORT . ACTIONS . TYPE . TASK_REOPENED ,
message
);
const hasOutstandingChildTask =
taskReport ?. managerID === currentUserAccountID
? true
: parentReport ?. hasOutstandingChildTask ;
const optimisticData = [
{
onyxMethod: Onyx . METHOD . MERGE ,
key: ` ${ ONYXKEYS . COLLECTION . REPORT }${ taskReportID } ` ,
value: {
stateNum: CONST . REPORT . STATE_NUM . OPEN ,
statusNum: CONST . REPORT . STATUS_NUM . OPEN ,
lastVisibleActionCreated: reopenedTaskReportAction . created ,
lastMessageText: message ,
},
},
{
onyxMethod: Onyx . METHOD . MERGE ,
key: ` ${ ONYXKEYS . COLLECTION . REPORT }${ taskReport ?. parentReportID } ` ,
value: {
hasOutstandingChildTask ,
},
},
];
API . write ( WRITE_COMMANDS . REOPEN_TASK , parameters , {
optimisticData ,
successData ,
failureData ,
});
}
Editing Tasks
Update task details after creation:
Open Task
Navigate to the task you want to edit.
Edit Mode
Click the Edit button or any editable field.
Update Fields
Change the title, description, or assignee as needed.
Save
Click Save to apply changes.
// Edit task from src/libs/actions/Task.ts
function editTask ( report : OnyxTypes . Report , { title , description } : OnyxTypes . Task ) {
// Create the EditedReportAction on the task
const editTaskReportAction = ReportUtils . buildOptimisticEditedTaskFieldReportAction ({
title ,
description ,
});
// Parse title and description
const reportName = title
? ReportUtils . getParsedComment (
title ,
undefined ,
undefined ,
[ ... CONST . TASK_TITLE_DISABLED_RULES ]
)
: ( report ?. reportName ?? '' );
const parsedTitle = ( reportName ?? '' ). trim ();
const newDescription = typeof description === 'string'
? ReportUtils . getParsedComment ( description )
: report . description ;
const reportDescription = ( newDescription ?? '' ). trim ();
const optimisticData = [
{
onyxMethod: Onyx . METHOD . MERGE ,
key: ` ${ ONYXKEYS . COLLECTION . REPORT_ACTIONS }${ report . reportID } ` ,
value: {
[editTaskReportAction.reportActionID]: editTaskReportAction ,
},
},
{
onyxMethod: Onyx . METHOD . MERGE ,
key: ` ${ ONYXKEYS . COLLECTION . REPORT }${ report . reportID } ` ,
value: {
reportName: parsedTitle ,
description: reportDescription ,
pendingFields: {
... ( title && { reportName: CONST . RED_BRICK_ROAD_PENDING_ACTION . UPDATE }),
... ( description && { description: CONST . RED_BRICK_ROAD_PENDING_ACTION . UPDATE }),
},
},
},
];
API . write ( WRITE_COMMANDS . EDIT_TASK , parameters , {
optimisticData ,
successData ,
failureData ,
});
}
Changing Assignee
Reassign a task to a different team member:
// Change task assignee from src/libs/actions/Task.ts
function editTaskAssignee (
report : OnyxTypes . Report ,
parentReport : OnyxEntry < OnyxTypes . Report >,
sessionAccountID : number ,
assigneeEmail : string ,
currentUserAccountID : number ,
assigneeAccountID : number | null = 0 ,
assigneeChatReport ?: OnyxEntry < OnyxTypes . Report >,
) {
const editTaskReportAction = ReportUtils . buildOptimisticChangedTaskAssigneeReportAction (
assigneeAccountID ?? CONST . DEFAULT_NUMBER_ID
);
const optimisticReport = {
managerID: assigneeAccountID ?? report . managerID ,
pendingFields: {
... ( assigneeAccountID && { managerID: CONST . RED_BRICK_ROAD_PENDING_ACTION . UPDATE }),
},
participants: {
[currentUserAccountID]: {
notificationPreference:
[ assigneeAccountID , taskOwnerAccountID ]. includes ( currentUserAccountID )
? CONST . REPORT . NOTIFICATION_PREFERENCE . ALWAYS
: CONST . REPORT . NOTIFICATION_PREFERENCE . HIDDEN ,
},
},
};
// If assignee changed, create chat report action
if ( assigneeAccountID && assigneeAccountID !== report . managerID ) {
assigneeChatReportOnyxData = ReportUtils . getTaskAssigneeChatOnyxData (
currentUserAccountID ,
assigneeAccountID ,
report . reportID ,
assigneeChatReportID ,
report . parentReportID ,
reportName ?? '' ,
assigneeChatReport ,
);
}
API . write ( WRITE_COMMANDS . EDIT_TASK_ASSIGNEE , parameters , {
optimisticData ,
successData ,
failureData ,
});
}
Task States
Tasks can be in one of several states:
Open : Task is active and awaiting completionstateNum : CONST . REPORT . STATE_NUM . OPEN
statusNum : CONST . REPORT . STATUS_NUM . OPEN
Completed : Task has been marked as donestateNum : CONST . REPORT . STATE_NUM . APPROVED
statusNum : CONST . REPORT . STATUS_NUM . APPROVED
Cancelled : Task was deleted or cancelled// Task cancellation
const message = `deleted task: ${ report . reportName } ` ;
const optimisticCancelReportAction = ReportUtils . buildOptimisticTaskReportAction (
report . reportID ,
CONST . REPORT . ACTIONS . TYPE . TASK_CANCELLED ,
message
);
Task Notifications
Stay updated on task activity:
Assignment Receive a notification when a task is assigned to you
Comments Get notified when someone comments on your task
Completion Notification when your assigned task is completed
Reopening Alert when a completed task is reopened
Viewing Tasks
Task List
Access all your tasks from the main task view:
My Tasks : Tasks assigned to you
Created by Me : Tasks you’ve created
All Tasks : All workspace tasks (admins only)
Filtering Tasks
Filter tasks by:
Status (Open, Completed)
Assignee
Creation date
Parent report or conversation
Best Practices
Use action verbs and be specific:
Good: “Review Q3 expense report by Friday”
Bad: “Expense report”
Add Context in Description
Include relevant details, links, or background information in the task description to help the assignee understand requirements.
Assign to the Right Person
Assign tasks to individuals who have the authority and ability to complete them. Avoid assigning to generic roles.
Use Tasks for Action Items
Convert meeting notes and discussion points into tasks to ensure follow-through. Don’t let action items get lost in chat.
Mark tasks complete as soon as they’re done. This keeps everyone informed and maintains accurate task lists.
Quick Action Tasks
New Expensify suggests tasks based on your activity:
// Quick action task creation from src/libs/actions/Task.ts
function startOutCreateTaskQuickAction (
currentUserAccountID : number ,
reportID : string ,
targetAccountPersonalDetails : OnyxTypes . PersonalDetails ,
) {
clearOutTaskInfoAndNavigate (
currentUserAccountID ,
targetAccountPersonalDetails ,
reportID ,
undefined ,
true // skipConfirmation
);
}
// Track quick actions in Onyx
optimisticData . push ({
onyxMethod: Onyx . METHOD . SET ,
key: ONYXKEYS . NVP_QUICK_ACTION_GLOBAL_CREATE ,
value: {
action: CONST . QUICK_ACTIONS . ASSIGN_TASK ,
chatReportID: parentReportID ,
isFirstQuickAction: isEmptyObject ( quickAction ),
targetAccountID: assigneeAccountID ,
},
});
Next Steps
Mentions & Notifications Learn about @mentions and notification settings
Messaging & Threads Back to messaging features
Approval Workflows Understand how tasks integrate with approval workflows