Skip to content

Tags

chronicle.tags is an org-level keyword vocabulary for discovery: you create a tag once in a scope, apply it to assets and experiments, and it feeds search.

A tag lives in a scope (your personal scope by default, or a team/org scope you can act as). Tagging an object touches no ACLs — who may tag is gated by Write on the object, who may grow a scope's vocabulary by act-as access on the scope. Tag names are denormalized into the search index, so chronicle.search(filters={"tags": [...]}) filters on them.

Build the vocabulary

create is find-or-create: the same (scope, normalized-name) always returns the one canonical row, so it's safe to call from any worker.

solver = chronicle.tags.create("pde-solver")                     # personal scope
ablation = chronicle.tags.create("ablation", scope_id=org_scope_id)

The record is {id, scope_id, name, normalized, created_by, created_at}.

list autocompletes a scope's vocabulary; q is a prefix on the normalized slug, and every row carries a usage_count.

for tag in chronicle.tags.list(scope_id=org_scope_id, q="base"):
    print(tag["name"], tag["usage_count"])                        # -> baseline 14
Method Signature Returns
create create(name, *, scope_id=None) tag record
list list(*, scope_id=None, q=None) list of tag records
get get(tag_id) tag record
rename rename(tag_id, name) tag record
delete delete(tag_id) result

rename renames the tag in one place and re-stamps every object carrying it in the search index; it needs act-as access on the tag's scope. delete cascades — it removes the tag and all of its taggings.

Apply tags to objects

Tag an asset or an experiment by name (tag= — find-or-created in that object's scope) or by an existing id (tag_id=). Pass exactly one; passing both, or neither, raises ValueError. Both calls require Write on the target.

chronicle.tags.tag_experiment(exp_id, tag="baseline")            # by name
chronicle.tags.tag_asset(checkpoint_id, tag_id=solver["id"])     # by id
Method Signature
tag_asset tag_asset(asset_id, *, tag=None, tag_id=None)
untag_asset untag_asset(asset_id, tag_id)
asset_tags asset_tags(asset_id)
tag_experiment tag_experiment(experiment_id, *, tag=None, tag_id=None)
untag_experiment untag_experiment(experiment_id, tag_id)
experiment_tags experiment_tags(experiment_id)

Untagging is always by tag_id. The *_tags readers return the list of tags applied to that object.

chronicle.tags.untag_experiment(exp_id, ablation["id"])
tags = chronicle.tags.asset_tags(checkpoint_id)                  # list of tag records

Discover what carries a tag

objects is the reverse lookup — everything a tag is applied to, across both object kinds:

hits = chronicle.tags.objects(ablation["id"])
hits["assets"]          # [...]
hits["experiments"]     # [...]

Tip

objects answers "what did we tag ablation?" directly. To rank or full-text-search across results, go through chronicle.search with filters={"tags": ["ablation"]} instead — the tag names are indexed for exactly that.