Tags
Ownership in Introspection is per-member: a file owned by one end user is invisible to every other. That is right for personal data and wrong for shared working material, such as a team’s documents, a customer-wide knowledge base, or a memory file several agents maintain together.
A share grants one file, issue, or conversation to a grantee. When the grantee is a tag, the share admits every member who holds that tag, so the cohort can change without touching the share. Adding someone to the cohort is one tag on their member, and removing them is taking it away.
No tag key is reserved, none is interpreted, and nothing is derived from a tag’s text. A tag means exactly what your organization decides it means, and two tags are related only by being equal.
Sharing with a cohort
Sharing a resource with a cohort takes two steps:
- An organization owner gives each member of the cohort the same tag, such as
team:acme. See Writing tags. - The resource’s owner creates a share that names that tag as its grantee.
CLI
introspection shares create --resource-type file --resource-id "$FILE_ID" \
--tag team:acmeEvery member whose tags include team:acme now sees the file in their ordinary
file list. A share admits; the caller’s scopes decide: a member whose token
holds files:write can update the file, one holding files:delete can delete
it, and one with only files:read can only read it. No share lets a grantee
change the file’s tags or manage its shares.
Three rules keep a tag share from reaching further than you intend:
- You must hold the tag. Creating a tag share requires owning the resource and holding the tag yourself, unless you’re an admin. You can’t see which members hold a tag, so this rule stops a typo or a guessed tag from opening a resource to a cohort you have never seen.
- A member and a tag narrow each other. A share that names both a member and a tag admits only that member, and only while they hold the tag.
- One live share per tag. Creating a second live share for the same
resource and tag returns
409. What a share admits never changes in place; revoke it and create another.
A tag share names one resource. Tagging another file with team:acme doesn’t
share it, so each resource the cohort should reach needs its own share.
Implicit tag access is deprecated
Today, a member whose tags intersect a task’s or a file’s tags can still read and write that row without any share. This implicit tag access is deprecated and will be removed. Use a tag share for anything a cohort needs to reach, and treat tags on tasks and files as labels for filtering and grouping.
Until implicit access is removed, a tag used for filtering also grants access
when the same string appears on a member. If you tag files env:prod to filter
them and also tag a member env:prod, that member can read and write those
files. Keep the two vocabularies apart, and audit with the reads in
Who can reach what.
A member admitted by implicit tag access can update a row’s content, title,
metadata, and lifecycle state, and can perform the ordinary recoverable delete.
They can’t change the row’s tags, because a patch that supplies tags matches
no row unless they own it.
Who writes which tags
Which side you’re writing decides how privileged the write is:
| You are writing | Who may write it | What it does |
|---|---|---|
| A task or file’s tags | The row’s owner, or a privileged caller | Labels the row for filtering and grouping |
| A member’s tags | An organization owner (members:manage) | Makes the member eligible for every tag share naming that tag |
Only an organization owner can put a tag on a member, and a tag share admits only members who hold its tag. Together with the rule that a share’s creator must hold the tag, a tag share can reach only a cohort that an organization owner already defined.
Writing tags
| Where | How | Available in |
|---|---|---|
| Task, at creation | tags on task create | SDKs, CLI (--tag), REST |
| Task, later | tags on task update | SDKs, REST |
| File, at creation | tags on file upload or create | REST |
| File, later | tags on file update | SDKs, REST |
| Member | tags on member create or update, organization owner only | Dashboard, REST |
| A member an identity assertion is about to mint | identity.tags when opening a runner | SDKs, CLI (--identity-tag), REST |
Tagging a member is the one write with no SDK surface: it is an organization-owner operation, done from the dashboard or with a REST call. That asymmetry is deliberate, because a member’s tags decide which tag shares admit them. See Who writes which tags.
The CLI sets tags when it creates a task, but does not filter a list by one; reach for an SDK or REST for that.
A tag list replaces wholesale. Omit tags to leave the existing list
untouched; pass [] to clear it. This is unlike a metadata patch, which merges
— so an explicit empty list has to reach the wire, and a client that drops falsy
values from a request body will silently fail to clear a tag.
CLI
introspection tasks create --runtime support-agent --environment production \
--prompt "Draft the Q3 summary." --tag customer:acme --tag team:researchTags on a file follow the file, not the version
A file’s versions are separate rows and a list returns the head, so a new version inherits both the tags and the owner of the version before it. Without that, a tag filter would silently stop matching at v2 because the new head was never tagged. A share follows the file the same way: it covers every version, so a grantee keeps access after someone adds a new one. Writing a new version records who wrote it separately from who owns it, so a writer admitted by a share never quietly takes ownership of a file.
Tags sent with POST /v1/files apply only when that request creates the file.
Adding a version keeps the file’s tags; sending a different set returns 409,
so change them with PATCH /v1/files/{id}.
What a tag may contain
A tag is an opaque string. key:value is the convention every example here
uses, and the one to follow — but it is only a convention: a bare acme is an
equally valid tag, because set membership does not care.
| Rule | Value |
|---|---|
| Maximum length | 128 characters |
| Maximum tags per resource | 64 |
| Must be | Non-empty, free of whitespace and control characters |
| Matching | Exact and case-sensitive — Acme and acme are two different tags |
| Duplicates | Collapsed; the remaining order is preserved |
Invalid tags are rejected, not trimmed. Silently turning "acme " into
"acme" would store a tag you never sent, which could make you eligible for a
tag share you never asked for. Nothing is normalized or lower-cased for the same
reason: normalizing would be one more thing reading a tag’s text.
Filtering
tag is an optional filter on the task, file, and member list endpoints:
for await (const task of runner.tasks.list({ tag: "customer:acme" })) {
console.log(task.id, task.tags);
}
for await (const file of runner.files.list({ tag: "customer:acme" })) {
console.log(file.name, file.tags);
}The filter only narrows. It is combined with the access rule rather than replacing it, so naming a tag you do not carry returns nothing rather than granting you anything.
Who can reach what
These reads answer the audit question for a tag:
GET /v1/members?tag=team:acmelists the members who hold the tag.GET /v1/shares?granted_tag=team:acmelists the shares that admit them.GET /v1/tasks?tag=team:acmeandGET /v1/files?tag=team:acmelist the rows carrying the tag, which implicit tag access still opens to those members.
Nothing joins them, and there is no group registry to enumerate. Members live in the Control Plane while shares, tasks, and files live in the Data Plane, which is also why the caller’s tags travel in the session token rather than being looked up.
Removing a member’s tag is eventual. Because the caller’s tags ride the
session token, removing a member’s tag takes effect at the next token mint,
the same as changing a member’s role. Revoking a share with
DELETE /v1/shares/{id} takes effect on the next request.
Tagging a customer as they arrive
When your backend opens a runner and asserts an end-user identity, identity.tags
stamps the customer member that assertion mints. That puts your end user into
a cohort at the moment they first appear, instead of asking an organization owner
to tag them afterwards, so tag shares for that cohort admit them from their
first session.
CLI
introspection tasks create --runtime support-agent --environment production \
--subject user_123 --identity-tag customer:acme --prompt "Draft the Q3 summary."--identity-tag requires --subject: tags stamp the member an identity mints,
so with no identity asserted there is no member to stamp.
Two bounds make this safe, and both are enforced by the server:
- Attenuated. The asserted list is narrowed to the tags the asserting agent member already holds; anything else is dropped silently. An assertion can only hand out what an organization owner already granted, so a tag still originates in exactly one place. Excess tags are dropped rather than raising, since the list is a hint about a customer and failing a whole session over one ungrantable tag would turn a typo into an outage.
- Applied on create only. Tags are stamped when the member row is first inserted and never on a later assertion. A returning customer cannot be re-tagged, stripped, or have an owner’s grant clobbered by a repeat call. Changing an existing member’s tags stays an owner operation.
This grants nothing until an organization owner deliberately tags the agent member: an agent member with no tags of its own can assert none.
Choosing between tags and shares
| Need | Use |
|---|---|
| Let one named person read one file, issue, or conversation | A share naming their member id |
| Let one named person edit a file or issue | A write share naming their member id |
| Let a changing group reach a resource | A tag on each member of the group, and a share naming that tag on the resource |
| Group work for filtering and reporting | A tag on the tasks and files |
| Let someone reproduce work from a conversation | A share, then a fork |
Related
- State & artifacts: files, shares, forks, and owner-scoped memory.
- Tasks & runs: the executions tags are set on.
- Authentication & identity: how a caller establishes the identity a tag is stamped on.
- Organizations & projects: members, roles, and the owner role that writes member tags.