# Principal and authority

Every agent acts as a known principal, within an authority scope you give it.

`AgentBuilder.build()` requires both. They are the agent's accountability wiring: the principal says who acts, and the scope says what that actor may do and for how long. A liability sink, which records each action, is optional.

## What the builder requires

* **`principal(AgentPrincipal)`**: the identity the agent acts as. `LocalIdentityProvider.issue(AgentDescriptor)` creates one for local use.
* **`authorityScope(AuthorityScope)`**: what the agent may do. `AuthorityScope.unrestricted(Duration)` allows every action type and target for a time window. `AuthorityScope.permanent()` never expires.
* **`liabilitySink(LiabilitySink)`**: optional. Without one, no liability records are built.

Without a principal or a scope, `build()` throws `IllegalStateException` and names the missing part. See [Create an agent](create.md) for a full builder chain.

## Wire a direct `Agent` subclass

A direct subclass does not go through the builder, so it wires its own `ActionExecutor`. Call `setPrincipal` and `setDefaultScope` on it and pass it to the four-argument `Agent` constructor. The [annotated agent example](create.md#write-an-annotated-agent-class) shows this.

An executor that is missing either one throws `AccountabilityWiringException` when an action is dispatched, before the action's body runs. It is not retried. In a chat, the turn ends on that tool call.

## Narrow the scope

<!-- java-contract: src/main/java/com/example/tnsai/docs/AuthorityScopeExample.java -->
```java
package com.example.tnsai.docs;

import com.tnsai.accountability.AuthorityScope;
import com.tnsai.enums.ActionType;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
import java.util.Set;

public final class AuthorityScopeExample {
    private AuthorityScopeExample() {}

    public static AuthorityScope localOnly() {
        return new AuthorityScope(
            Set.of(ActionType.LOCAL),
            Set.of("billing"),
            Optional.of(new BigDecimal("5.00")),
            Duration.ofHours(8),
            Instant.now());
    }
}
```

| Field | Meaning |
| --- | --- |
| `allowedActions` | Action types the agent may run. Empty allows all |
| `targetSystems` | Systems the agent may act on. Empty allows all |
| `spendCeilingUSD` | Spending limit, read by the x402 payment broker |
| `validFor` | How long the scope lasts from `issuedAt`. `null` never expires |
| `issuedAt` | When the scope starts |

## When the scope is checked

When a liability sink is set, the scope is recorded in each liability record. It is enforced only for actions that declare an access policy, with `@Security` or `@ExecutionPolicy` on the method or its class. For those actions:

* With `tnsai-quality` on the classpath, its `SecurityEnforcer` denies the call with a `SecurityException` when the scope has expired, does not permit the action type, or lists target systems that exclude the action's target.
* Without `tnsai-quality`, the call is refused, because no provider can evaluate the declared policy.

An action with neither annotation runs whatever its scope says. To bound one, declare a policy on it. See [Enforcement](../security/enforcement.md) and [Execution policy](../security/execution-policy.md).

## Related

- [Audit agent actions](../security/accountability.md): identity, liability records, tiers and reputation in depth.
- [Create an agent](create.md): the builder chain that sets the principal and scope.
- [Enforcement](../security/enforcement.md): which checks run on each action.
- [Restrict who can trigger an action](../security/execution-policy.md)
