Skip to content

Match people to attributes

A person’s Role, Level, Location and Company are not typed in one by one. Each of those attributes carries a match expression — a short rule written against the person’s own fields — and Resorcerer assigns the first attribute whose rule matches. Change the rules and every person is re-evaluated; add a person, or let an integration update one, and their attributes are worked out on the spot.

That is what keeps a directory of a thousand people consistent: the rule title:~engineer puts every engineer on the Engineer role, whether they came from a CSV, from Microsoft Entra, or from someone typing them in.

Open Roles, Levels, Locations or Companies under Configuration. Each row has three settings alongside its name:

Setting What it does
Match expression The rule. A person whose fields satisfy it gets this attribute. Leave it blank for an attribute that is only ever set by hand or used as the default.
Priority Evaluation order. Lower numbers run first; rows with the same priority run in name order. New rows start at 100.
Default Assigned when no expression matches. At most one default per attribute type — setting a new default replaces the previous one.

The list on each page is shown in evaluation order, top to bottom, so what you see is what runs.

How a person’s attributes are worked out

Section titled “How a person’s attributes are worked out”

For each of the four attribute types, whenever a person record is saved:

  1. The rows are evaluated in priority order, then by name. The first row whose expression matches the person wins.
  2. If nothing matches, the row marked Default is used, if there is one.
  3. Otherwise the attribute is left empty.

This happens every time a person is written — created or edited by hand, updated by a CSV import, synced from an integration, or changed through the API — so a person’s attributes always reflect their record as it is now. Editing an attribute’s expression, priority or default re-evaluates everyone in the organization at once.

An attribute you’ve overridden on a person is skipped by all of this until you set it back to automatic.

An expression refers to a person’s fields by name. Names are case-insensitive, and the aliases work anywhere the field name does.

Field Aliases Holds
name Full name
email mail Email address
title jobTitle Job title
department dept Department or team
company employer Company name as synced or entered — the free-text field, not the Company attribute
location office, site Office or location as synced or entered — the free-text field, not the Location attribute
externalId extId Identifier from the directory or HR system
externalName userName Username from the directory
isActive active true or false
startDate started, hired Start date
endDate ended, leaving End date
managerName manager The manager’s full name
managerEmail The manager’s email address
group team The name of any group the person is a direct member of
groupPath The full path of any group the person is a direct member of, from the root group down to that group (for example Engineering/Platform)

The company and location fields are worth a second look. They are the plain text that came from your directory or that someone typed — Contoso Ltd, Building 4, Reading — and they are the usual thing a Company or Location attribute’s rule matches on. The attribute is the tidy, shared value Resorcerer derives from them.

group and groupPath are worth a second look too. A person can belong to several groups at once, so both fields are multi-valued — the condition matches if any of a person’s direct group memberships satisfies it. group compares against each group’s own name (Platform), while groupPath compares against the full path from the root group down to it (Engineering/Platform), so groupPath:~Engineering catches anyone directly in Engineering or in a group nested underneath it, while group:Engineering only catches people directly in a group actually named Engineering.

Note this is different from the Group filters elsewhere in the app: the People list’s “Filter by group” is also direct-membership-only like group/groupPath here, but the Group picker in a live model’s people in scope is transitive — selecting a parent group there also includes everyone in its sub-groups. Match expressions never include sub-group members implicitly; use groupPath:~<name> if you want that.

Every condition is field:value. Text comparisons ignore case.

Expression Matches people whose…
department:Engineering department is exactly Engineering
title:~engineer title contains engineer anywhere
email:*@contractor.com email ends in @contractor.com — * stands for any run of characters, ? for exactly one
location:"New York" location is New York — quote a value that has spaces in it
title:!Intern title is anything other than Intern
manager:null manager is empty (a blank text value counts as empty)
endDate:* end date has a value
isActive:false record is inactive
startDate:<2024-01-01 start date is before 1 January 2024
startDate:[2024-01-01 TO 2024-12-31] start date falls within 2024, inclusive
startDate:[2024-01-01 TO *] start date is on or after 1 January 2024 — * leaves an end open

Wildcards also work inside a contains match (title:~*eng*), and >, >=, < and <= all apply to dates. Ordering comparisons are for dates only; using one on a text field is an error. There is no regular-expression syntax.

Write a date as YYYY-MM-DD. startDate:2024-06-01 means that whole day, and startDate:<2024-06-01 means before it.

Dates can also be relative to today:

Expression Means
startDate:>now-90d started within the last 90 days
startDate:<now-1y started more than a year ago
endDate:[now TO now+30d] leaving in the next 30 days

The units are h (hours), d (days), mo (months) and y (years). Plain m is rejected — it is ambiguous between minutes and months — so write mo for months.

Expression Means
department:Sales title:~manager both — whitespace between conditions is an implicit AND
department:Sales AND title:~manager the same, spelled out
department:Sales OR department:Marketing either
NOT title:~lead negation
(department:Sales OR department:Marketing) AND NOT title:~lead grouping

&&, ||, ! and a leading - are accepted as alternatives to AND, OR and NOT. Every term must be a condition: a bare word such as engineer on its own, with no field in front of it, is an error rather than a free-text search.

Priority is how you make a specific rule beat a general one. Say every title containing engineer should be Engineer, except staff engineers:

Role Match expression Priority
Staff Engineer title:~"staff engineer" 10
Engineer title:~engineer 100

Priority 10 runs before 100, so a Staff Engineer, Platform lands on the first row and everyone else with engineer in their title on the second.

The Default catches whoever is left. A company called Example Ltd marked as the default Company gives every person a company unless a rule says otherwise — which is usually the right thing for a workforce that is mostly your own employees plus a few contractors matched by email:*@contractor.com.

An attribute with no expression and no default flag is never assigned automatically. It can still be chosen by hand as an override, which is the right shape for a rare exception you never want a rule to produce.

Sometimes the rule is right for everyone except one person. Rather than complicate the expression, open that person from the People page and expand Attribute overrides. Each of the four attributes offers:

  • Automatic — the derived value, shown next to the word so you can see what the rules currently produce. This is the normal setting.
  • None (override) — pin the attribute to empty, even if a rule would match.
  • A specific row — pin that attribute regardless of the rules.

An overridden attribute shows an Override badge in the person’s row on the People page. It stays exactly as you set it — through imports, syncs and rule changes — until you set it back to Automatic.

Overrides work on people managed by an integration too. The integration owns the person’s text fields (title, department, company, location and so on), but the attributes derived from them are always yours to pin.

Two other actions create overrides as a side effect, because each is an explicit choice about a person:

  • Fixing an attribute mismatch from the Problems view by copying the position’s attributes onto the person.
  • Filling one of the roleattribute, levelattribute, locationattribute or companyattribute columns in a CSV import.

The expression editor helps as you type:

  • Autocomplete offers field names as soon as you start a condition.
  • The help button beside the field opens a syntax cheat sheet with the examples above.
  • A live Matches N of M people count updates as you type, with a sample of who matched, so you can see whether title:~eng is catching the English teachers too.

An expression that can’t be understood is underlined at the exact position of the problem, with a message saying what’s wrong — an unknown field name comes with suggestions for the fields that do exist. It can’t be saved until it’s fixed.

Editing a rule re-evaluates the whole organization automatically. If you ever want to force that — after a large import, say, or to be sure the People page reflects the rules as they stand — use Recompute attributes on the People page. It re-derives every attribute that isn’t overridden and tells you how many people changed. Overrides are left alone.

Import people accepts both kinds of value:

  • company and location columns fill the free-text fields the rules match on.
  • roleattribute, levelattribute, locationattribute and companyattribute name an attribute row to pin as an override for that person.

A blank attribute cell means derive it — it clears any existing override on that person and lets the rules decide. A value that doesn’t match an existing row is left unmatched (and reported) unless you let the import create it.

The rules use one expression language, evaluated the same way whether a person is saved from the app, imported, synced or written through the API. Scripts can try an expression exactly as the editor does, through the GraphQL API:

query {
personAttributeMatchPreview(kind: ROLE, expression: "title:~engineer", sampleSize: 5) {
matchCount
totalCount
sample { name email title department }
error { message position suggestions }
}
}

personQueryFields lists the fields and aliases above, and the recomputePersonAttributes mutation does what the Recompute attributes button does. An AI agent gets the same two things as MCP tools: GetMatchExpressionSyntax returns this page’s operators and field list, and PreviewMatchExpression tries a rule and reports the count, a sample, or the error. Roles, levels, locations and companies expose matchExpression, matchPriority and isDefault on every surface, and a person’s attributes come back as roleAttributeId, levelAttributeId, locationAttributeId and companyAttributeId, each with an is…Override flag. See APIs.

Attributes that were already assigned to people are kept as overrides, so nothing changes on its own. Once your rules are in place, set people back to Automatic — or use Recompute attributes after clearing overrides — to let the rules take over.