Capability Selection

In the first guide, we used tags to apply behavior to data. In this guide, we take the next step: tags can also select which behavior applies.

This is where Tagex starts to look less like data cleanup and more like a semantic control mechanism.

The Problem: the Same Data, Different Meaning

In real systems, the same struct often needs to behave differently depending on context:

  • Free vs paid users
  • Development vs production
  • Internal vs external consumers
  • Different deployment tiers

This logic is usually implemented with conditionals scattered across the codebase.

Declaring Capabilities with Tags

With Tagex, you can encode capability-dependent semantics directly on fields.


type JobConfig struct {
    MaxConcurrency int `cap:"limit, tier=premium"`
}

This tag does not say “this value must be valid”. It says:

Apply the limit directive using the premium tier.

Implementing a Capability-Aware Directive

A directive is free to consult external context: environment variables, configuration, licenses, or feature flags.


type LimitDirective struct {
    Tier string `param:"tier"`
}

func (d *LimitDirective) Name() string {
    return "limit"
}

func (d *LimitDirective) Mode() tagex.DirectiveMode {
    return tagex.MutMode
}

func (d *LimitDirective) Handle(val int) (int, error) {
    max := lookupLimitForTier(d.Tier)
    if val > max {
        return max, nil
    }
    return val, nil
}

This directive does not reject values. It adapts them to the declared capability.

Registering Capability Semantics


capTag := tagex.NewTag("cap")
tagex.RegisterDirective(&capTag, &LimitDirective{})

The same struct can now express different behavior without conditional logic in application code.

Context-Sensitive Processing


cfg := JobConfig{
    MaxConcurrency: 32,
}

_, _ = capTag.ProcessStruct(&cfg)

Depending on the tier:

  • Free users might be capped at 4
  • Premium users might allow 16
  • Enterprise users might allow 64

The struct itself declares which semantics apply.

Why This Is Not Validation

At no point did we ask: “Is this value allowed?”

Instead, we asked:

What does this value mean under this capability?

The same input can legitimately result in different outcomes depending on context.

What Capability Selection Buys You

  • No scattered if tier == ... logic
  • No duplicated policy enforcement
  • Semantics live with the data they affect
  • Behavior is explicit and inspectable

Tags become a declarative interface between data and policy.

Looking Ahead

So far, directives have:

  • Normalized values
  • Selected behavior based on capabilities

In the next guide, we will look at what happens after all semantics have succeeded, and why Tagex’s post-processing model is such a powerful abstraction.