mdxui

Verbs

Understanding the action grammar - consistent naming for events, relations, and operations

Verbs

A Verb is a complete action grammar with all its forms. The Verb grammar provides consistent naming across events, relations, actions, and results throughout the system.


The Verb Grammar

Every Verb has 9 properties that define its complete action semantics:

PropertyDescriptionExample (create)Example (approve)
actorWho performscreatorapprover
actThe verbcreatesapproves
actionNoun formcreateapprove
activityGerund (-ing)creatingapproving
objectInput(the thing being created)(the thing being approved)
resultOutputcreationapproval
eventPast tensecreatedapproved
reverseReverse relationcreatedByapprovedBy
inverseOpposite actiondeletereject

Why Verb Grammar?

The Verb grammar solves a common problem in software: inconsistent naming.

Without Verb Grammar

// Inconsistent naming
interface Task {
  creator: User        // actor form
  created: Date        // event form
  createdDate: Date    // redundant
  createTime: Date     // more redundancy
}

// Events have different patterns
type Events =
  | { type: 'TaskCreated' }        // past tense
  | { type: 'ApprovalReceived' }   // noun form
  | { type: 'Completing' }         // gerund form
  | { type: 'Delete' }             // verb form

With Verb Grammar

// Consistent naming
interface Task {
  creator: User        // actor
  createdAt: Date      // event + At
  createdBy: User      // reverse relation
}

// Events follow pattern: {Noun}{Event}
type Events =
  | { type: 'TaskCreated' }
  | { type: 'TaskApproved' }
  | { type: 'TaskCompleted' }
  | { type: 'TaskDeleted' }

The 9 Forms Explained

1. Actor (Who)

The person or system that performs the action.

VerbActorUsage
createcreatortask.creator
approveapproverinvoice.approver
completecompletertask.completer
assignassignertask.assigner
reviewreviewerpr.reviewer
deletedeleterrecord.deleter

2. Act (Present Tense Verb)

The action in present tense, third person singular.

ActorActUsage
creatorcreates"Creator creates Task"
approverapproves"Approver approves Invoice"
completercompletes"Completer completes Task"
assignerassigns"Assigner assigns Task"

3. Action (Verb Noun)

The command or imperative form.

ActionUsage
createawait create(task)
approveawait approve(invoice)
completeawait complete(task)
assignawait assign(task, user)
deleteawait delete(record)

4. Activity (Gerund -ing)

The ongoing process form.

ActivityUsage
creating"Creating Task..."
approving"Approving Invoice..."
completing"Completing Task..."
assigning"Assigning Task..."

Used in:

  • UI loading states: "Creating your account..."
  • Progress indicators: "Approving invoice..."
  • Log messages: "Creating product..."

5. Object (Input)

The thing being acted upon.

ActionObject
createTask data
approveInvoice
completeTask
assignTask + User

6. Result (Outcome Noun)

The outcome or artifact of the action.

ActionResultUsage
createcreationconst creation = await create(task)
approveapprovalconst approval = await approve(invoice)
completecompletionconst completion = await complete(task)
assignassignmentconst assignment = await assign(task, user)
deletedeletionconst deletion = await delete(record)

7. Event (Past Tense)

The event name when the action occurred.

EventUsage
createdTaskCreated, ProductCreated
approvedInvoiceApproved, ProposalApproved
completedTaskCompleted, WorkflowCompleted
assignedTaskAssigned, RoleAssigned
deletedTaskDeleted, UserDeleted

Event pattern: {Noun}{Event}

8. Reverse (Inverse Relation)

The reverse relationship for lookups.

EventReverseUsage
createdcreatedBytask.createdBy (who created it)
approvedapprovedByinvoice.approvedBy
completedcompletedBytask.completedBy
assignedassignedBytask.assignedBy
deleteddeletedByrecord.deletedBy

9. Inverse (Opposite Action)

The action that undoes or opposes the original.

ActionInverseRelationship
createdeleteCreate ↔ Delete
approverejectApprove ↔ Reject
assignunassignAssign ↔ Unassign
archiverestoreArchive ↔ Restore
enabledisableEnable ↔ Disable
startstopStart ↔ Stop
opencloseOpen ↔ Close

Common Verbs

Lifecycle Verbs

ActionActorEventInverse
createcreatorcreateddelete
updateupdaterupdatedrestore
deletedeleterdeletedrestore
archivearchiverarchivedrestore
restorerestorerrestoredarchive

Workflow Verbs

ActionActorEventInverse
startstarterstartedstop
pausepauserpausedresume
resumeresumerresumedpause
completecompletercompletedreopen
cancelcancelercanceledrestart

Approval Verbs

ActionActorEventInverse
submitsubmittersubmittedwithdraw
approveapproverapprovedreject
rejectrejecterrejectedapprove
reviewreviewerreviewed-

Assignment Verbs

ActionActorEventInverse
assignassignerassignedunassign
claimclaimerclaimedunclaim
delegatedelegatordelegatedreclaim

State Verbs

ActionActorEventInverse
enableenablerenableddisable
disabledisablerdisabledenable
activateactivatoractivateddeactivate
publishpublisherpublishedunpublish
locklockerlockedunlock

Usage in Code

Events

// Event pattern: {Noun}{Event}
type TaskEvent =
  | { type: 'TaskCreated', task: Task }
  | { type: 'TaskAssigned', task: Task, assignee: User }
  | { type: 'TaskCompleted', task: Task }
  | { type: 'TaskApproved', task: Task, approver: User }
  | { type: 'TaskRejected', task: Task, reason: string }
  | { type: 'TaskDeleted', taskId: string }

Relations

interface Task {
  id: string
  title: string

  // Actor relations
  creator: User          // actor
  assignee?: User        // actor

  // Reverse relations
  createdBy: User        // reverse
  assignedBy?: User      // reverse
  approvedBy?: User      // reverse

  // Timestamps (event + At)
  createdAt: Date        // event
  assignedAt?: Date      // event
  completedAt?: Date     // event
  approvedAt?: Date      // event
}

Actions

// Action pattern: {action}({object}): Promise<{result}>
async function create(data: CreateTaskInput): Promise<Task> {
  const task = await db.tasks.create(data)
  await emit({ type: 'TaskCreated', task })
  return task
}

async function assign(taskId: string, userId: string): Promise<Task> {
  const task = await db.tasks.update(taskId, { assignee: userId, assignedAt: new Date() })
  await emit({ type: 'TaskAssigned', task, assignee: userId })
  return task
}

async function complete(taskId: string): Promise<Task> {
  const task = await db.tasks.update(taskId, { status: 'completed', completedAt: new Date() })
  await emit({ type: 'TaskCompleted', task })
  return task
}

UI States

// Activity form for loading states
const [state, setState] = useState<
  | { status: 'idle' }
  | { status: 'creating' }      // activity
  | { status: 'created', task: Task }  // event
  | { status: 'error', error: Error }
>({ status: 'idle' })

function handleSubmit() {
  setState({ status: 'creating' })
  create(data)
    .then(task => setState({ status: 'created', task }))
    .catch(error => setState({ status: 'error', error }))
}

Verb Collections

The system has a verbs collection to define standard verbs:

interface Verb {
  id: string
  actor: string       // "creator"
  act: string         // "creates"
  action: string      // "create"
  activity: string    // "creating"
  result: string      // "creation"
  event: string       // "created"
  reverse: string     // "createdBy"
  inverse?: string    // "delete"
}

Standard verbs are pre-defined:

const verbs: Verb[] = [
  {
    actor: 'creator',
    act: 'creates',
    action: 'create',
    activity: 'creating',
    result: 'creation',
    event: 'created',
    reverse: 'createdBy',
    inverse: 'delete',
  },
  {
    actor: 'approver',
    act: 'approves',
    action: 'approve',
    activity: 'approving',
    result: 'approval',
    event: 'approved',
    reverse: 'approvedBy',
    inverse: 'reject',
  },
  // ... more standard verbs
]

Naming Patterns

Database Fields

PatternExampleUsage
{actor}creator, approverWho performed action
{event}AtcreatedAt, approvedAtWhen action occurred
{event}BycreatedBy, approvedByWho performed (reverse relation)

Event Types

PatternExample
{Noun}{Event}TaskCreated, InvoiceApproved
{Noun}{Event}UserRegistered, PaymentCompleted

Function Names

PatternExampleReturns
{action}create(), approve()The result entity
{action}{Noun}createTask(), approveInvoice()The result entity

UI Copy

PatternExample
{Activity}..."Creating task...", "Approving invoice..."
{Event}!"Created!", "Approved!"
{Action} {Noun}"Create Task", "Approve Invoice"

Workflow State Machines

Verbs define state transitions in workflows:

const taskWorkflow = {
  states: {
    draft: {
      on: {
        submit: { target: 'submitted', actions: ['notifyReviewer'] }
      }
    },
    submitted: {
      on: {
        approve: { target: 'approved', actions: ['notifyCreator'] },
        reject: { target: 'rejected', actions: ['notifyCreator'] },
        withdraw: { target: 'draft' }
      }
    },
    approved: {
      on: {
        start: { target: 'in_progress', actions: ['assignWorker'] }
      }
    },
    in_progress: {
      on: {
        complete: { target: 'completed', actions: ['notifyStakeholders'] },
        pause: { target: 'paused' }
      }
    },
    paused: {
      on: {
        resume: { target: 'in_progress' }
      }
    },
    completed: {
      on: {
        reopen: { target: 'in_progress' }
      }
    },
    rejected: {
      on: {
        resubmit: { target: 'submitted' }
      }
    }
  }
}

Each transition uses a Verb:

  • submit, approve, reject, start, complete, pause, resume, reopen

Benefits

1. Consistency

All events, relations, and actions follow the same pattern.

2. Predictability

If you know the verb "create", you can predict:

  • Event: TaskCreated
  • Relation: task.createdBy
  • Timestamp: task.createdAt
  • Action: await create(task)

3. Type Safety

TypeScript can enforce the grammar:

type VerbGrammar<T extends string> = {
  actor: `${T}er`
  act: `${T}s`
  action: T
  activity: `${T}ing`
  event: `${T}ed`
  reverse: `${T}edBy`
}

type CreateVerb = VerbGrammar<'create'>
// {
//   actor: "createer"  // ❌ TypeScript would catch this
//   ...
// }

4. Internationalization

The grammar provides clear translation keys:

{
  "verb.create.actor": "creator",
  "verb.create.activity": "creating",
  "verb.create.event": "created"
}

5. Auto-generated UI

Components can render automatically from Verb grammar:

function ActionButton({ verb, noun }: { verb: Verb, noun: string }) {
  return <Button>{verb.action} {noun}</Button>
}

// Renders: "Create Task", "Approve Invoice", "Complete Order"

Advanced Patterns

Composite Verbs

Some actions are compositions:

// reassign = unassign + assign
async function reassign(taskId: string, fromUserId: string, toUserId: string) {
  await unassign(taskId, fromUserId)
  await assign(taskId, toUserId)
}

Contextual Verbs

Same verb, different contexts:

// Task approval
await approve(task)  // TaskApproved

// Invoice approval
await approve(invoice)  // InvoiceApproved

// Pull request approval
await approve(pullRequest)  // PullRequestApproved

Chained Verbs

Workflows chain verbs:

// create → submit → approve → start → complete
const task = await create({ title: "Write docs" })
await submit(task.id)
await approve(task.id)
await start(task.id)
await complete(task.id)

Next Steps

  • Read Nouns to understand the entities that Verbs act upon
  • See Workflows for state machines built on Verbs
  • Explore Types for the type system

On this page