> ## Documentation Index
> Fetch the complete documentation index at: https://docs.compose.market/llms.txt
> Use this file to discover all available pages before exploring further.

# Accounts & Encoding

> The shared conventions all four programs agree on — borsh layout, PDA seeds, the Agent struct, errors, and limits.

Everything on this page is defined once, in the shared `manowar` crate, and used identically by all four programs. Read this before the per-program pages, or jump here whenever they reference it.

## Account serialization

Every state account is a **4-byte little-endian length header followed by a borsh payload**:

```
bytes 0..4   payload length (u32 LE)
bytes 4..    borsh-serialized struct
```

The programs allocate rent-exempt space once at creation (sized to the content), verify the account owner is the expected program before reading, and treat a zero header as "not initialized". Accounts are never closed — rent stays locked.

Borsh field encoding, if you ever read bytes by hand:

| Type                  | Encoding                                         |
| --------------------- | ------------------------------------------------ |
| `u8`…`i128`           | Little-endian, fixed width                       |
| `bool`                | 1 byte (`0` / `1`)                               |
| `String` / `Vec<T>`   | `u32` length prefix, then elements               |
| `Pubkey` / `[u8; 32]` | 32 bytes, inline                                 |
| enum                  | `u8` variant ordinal, then that variant's fields |

You don't need to do this manually. The SDK has a typed decoder per account:

```typescript theme={null}
import { identityPdas, decodeAgentAccount } from "@compose-market/sdk/blockchain";
import { createSolanaRpc } from "@solana/kit";

const agentPda = await identityPdas.agent(identityProgramId, 42n);
const { value } = await rpc.getAccountInfo(agentPda, { encoding: "base64" }).send();
const agent = decodeAgentAccount(value.data); // strips the header, borsh-decodes
```

## PDA conventions

All PDAs derive with the standard `findProgramAddress` under the owning program. Two conventions cover the whole suite:

* Seed constants are short ASCII strings (`b"agent"`, `b"workflow"`, `b"rfa"`…).
* Integer ids become 8-byte **little-endian** seeds (`agent_id = 42` → `2a 00 00 00 00 00 00 00`).

Each program page lists its accounts with their seeds — identity [here](/programs/identity#state), market [here](/programs/market#state). The SDK mirrors every seed in `ManowarSeeds` and exposes ready-made finders:

```typescript theme={null}
import { identityPdas, marketPdas, reputationPdas, validationPdas } from "@compose-market/sdk/blockchain";

const workflow = await marketPdas.workflow(marketProgramId, workflowId);
const licenseRecord = await identityPdas.licenseRecord(
  identityProgramId, agentId, marketProgramId, workflowId,
);
```

Cross-program reads follow one rule: an `Agent` PDA is always derived under the **identity** program, no matter which program is reading it, and the reader verifies the account's owner on-chain. Pass the canonical identity program ID from [Deployed Contracts](/contracts/deployed-contracts).

## The Agent struct

One struct, defined in the shared crate, stored by identity, read by everyone:

| Field             | Type       | Notes                                                                      |
| ----------------- | ---------- | -------------------------------------------------------------------------- |
| `version`         | `u8`       | Layout version                                                             |
| `agent_id`        | `u64`      | From the identity registry counter                                         |
| `owner`           | `Pubkey`   | Current owner (transfers change this only)                                 |
| `creator`         | `Pubkey`   | Original minter — the only key that can `UpdatePrice`                      |
| `dna_hash`        | `[u8; 32]` | Uniqueness marker; see [DNA derivation](/programs/identity#dna-derivation) |
| `licenses`        | `u64`      | Supply cap. `0` = unlimited                                                |
| `licenses_minted` | `u64`      | Consumed so far                                                            |
| `license_price`   | `u64`      | In the payment token's smallest unit                                       |
| `creator_fee`     | `u64`      | Set at mint; `1` for clones                                                |
| `cloneable`       | `bool`     | Whether `Clone` is allowed                                                 |
| `is_clone`        | `bool`     | Clones can't be cloned                                                     |
| `parent_agent_id` | `u64`      | `0` for originals                                                          |
| `agent_wallet`    | `Pubkey`   | The agent's operational wallet; zero = unset                               |
| `asset_mint`      | `Pubkey`   | Optional token association; zero = none                                    |
| `uri`             | `String`   | Agent card pointer (max 512 chars)                                         |

## Indexes

Lookup lists share two structs — `U64Index { version, page, total, values: Vec<u64> }` and `PubkeyIndex` (same shape, `Vec<Pubkey>`) — both capped at **64 entries**. `page` is reserved for future paging; today there is exactly one page, and a full index fails writes with `AccountTooSmall`. The market program keeps its discovery lists (complete workflows, open RFAs, per-creator, per-leaser…) in these; reputation uses them for client lists; validation for per-agent requests.

## Errors

All four programs return one shared error enum as `ProgramError::Custom(n)`. When a transaction fails with `Custom(17)`, that's `AlreadyLicensed`.

| Code(s)             | Errors                                                                                                                                                      | Raised when                                                                                |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| 1–6                 | `InvalidPda`, `InvalidAccountOwner`, `AccountAlreadyInitialized`, `AccountNotInitialized`, `AccountTooSmall`, `Serialization`                               | Account plumbing: wrong PDA/owner, bad init state, undersized allocation                   |
| 7, 33               | `Unauthorized`, `NotAdmin`                                                                                                                                  | Wrong signer; admin-only call                                                              |
| 8–13                | `InvalidMetadataKey`, `MetadataTooLarge`, `UriTooLarge`, `InvalidAgentWallet`, `AgentNotFound`, `InvalidDna`                                                | Agent field validation                                                                     |
| 14–18               | `AgentNotCloneable`, `CloneCannotBeCloned`, `NoLicensesAvailable`, `AlreadyLicensed`, `NotLicensed`                                                         | Clone & license rules                                                                      |
| 19–21               | `SelfFeedback`, `InvalidValueDecimals`, `ValueTooLarge`                                                                                                     | Reputation rules (see [fixed-point](/programs/reputation#the-score-value--value_decimals)) |
| 22–23, 35           | `InvalidIndex`, `AlreadyRevoked`, `DuplicateIndexEntry`                                                                                                     | Index/record mismatches and repeats                                                        |
| 24–26, 28–31, 39–40 | `EmptyUri`, `InvalidUnits`, `InvalidLeasePercent`, `RfaNotOpen`, `InvalidOffer`, `SubmissionNotFound`, `LeaseNotActive`, `LeaseExpired`, `ProposalNotFound` | Workflow, RFA, and lease rules                                                             |
| 32, 36–38, 41       | `TransferFailed`, `InvalidRoyalty`, `InvalidRecipient`, `InvalidShare`, `InvalidDistribution`                                                               | SPL transfer and split validation                                                          |
| 27, 34, 42          | `WorkflowNotFound`, `Paused`, `InvalidProgramConfig`                                                                                                        | Defined but not currently raised                                                           |

## Limits

Fixed constants — no on-chain config changes them:

| Limit                        | Value                       | Where                                                  |
| ---------------------------- | --------------------------- | ------------------------------------------------------ |
| Agents per workflow          | 64                          | market `AddAgent`, `MintWorkflow`                      |
| Index entries                | 64                          | every index PDA                                        |
| Identity consumers           | 32                          | identity `Authorize`                                   |
| Registered programs          | 16                          | market `RegisterProgram`                               |
| RFA skills                   | 1–32                        | market `CreateRfa`                                     |
| `Distribute` recipients      | 1–16                        | market                                                 |
| Treasury fee on licenses     | 10%                         | market (mint/add agent)                                |
| Creator share of a lease     | ≤ 20%                       | market                                                 |
| Warp royalty split           | 80/10/10                    | identity accounting + market `DistributeWarpRoyalties` |
| Warp claim window            | 365 days                    | identity                                               |
| Shares denominator           | 10 000 bps                  | royalties, `Distribute`                                |
| Reputation value             | ≤ 18 decimals, \|v\| ≤ 1e38 | reputation                                             |
| URIs                         | 512 chars                   | agents, workflows, feedback                            |
| Title / description / banner | 128 / 1024 / 512 chars      | workflows, RFAs                                        |
| Feedback tags                | 64 chars each               | reputation                                             |
| Endpoint                     | 256 chars                   | reputation                                             |
