# NoteManager

> The NoteManager is the local index of your [notes](/concepts/notes): what you have, each note's status, and the discovery cursor. It is held in the session's storage adapter, which you configure. Storage is not configured by default, so without a `persistentStorage` config the index lives in memory only and is lost on reload.

The NoteManager is the local index of your [notes](/concepts/notes): what you have, each note's status, and the discovery cursor. It is held in the session's storage adapter, which you configure. Storage is not configured by default, so without a `persistentStorage` config the index lives in memory only and is lost on reload.

## Note status states

`INACTIVE` A draft or unclaimed note the session is aware of but cannot yet spend. The typical case is a recipient-side draft generated as part of a send, before the corresponding commitment lands on-chain or is imported.
`PENDING` The note exists locally but isn't spendable yet: a deposit is awaiting [ASP attestation](/concepts/asp-attestation), and a transact output is awaiting chain confirmation.
`ACTIVE` The note is attested and confirmed, so it is spendable.
`SPENT` The [nullifier](/concepts/commitments-and-nullifiers) has been published on-chain, and the note can't be re-spent.
`REJECTED` The ASP explicitly refused the deposit's label. The note is recoverable via [ragequit](/operations/ragequit).
`EXITED` The note has been ragequit and the public exit completed.

## Status transition matrix

The legal transitions are:

| From | To | Trigger |
|---|---|---|
| `INACTIVE` | `PENDING` | commitment observed on-chain |
| `INACTIVE` | `EXITED` | ragequit |
| `PENDING` | `ACTIVE` | attestation lands |
| `PENDING` | `ACTIVE` | discoverable-mode re-decryption |
| `PENDING` | `REJECTED` | attestation refuses |
| `PENDING` | `EXITED` | ragequit |
| `ACTIVE` | `SPENT` | transact submission lands |
| `ACTIVE` | `EXITED` | ragequit |
| `ACTIVE` | `REJECTED` | label revoked on the ASP after activation |
| `REJECTED` | `EXITED` | ragequit |

Illegal transitions throw `InvalidStatusTransitionError`. State can still drift if note updates aren't persisted before reload. The most common symptom is re-running discovery flipping `SPENT` back to `ACTIVE`. If you see balances refuse to decrease across a page reload, call `session.discoverNotes()`, which flushes the NoteManager internally. See [Failure modes](../dev-guide/failure-modes).

## Persistence

Choose one of these adapters through `persistentStorage`. None is selected by default, so until you set one the NoteManager keeps its index in memory only.

`{type: "local", prefix}` Browser localStorage, used only when you select this type. The default prefix is then `privacy-pool`, and the cursor and note state persist under keys carrying that prefix.
`{type: "file", dirPath, filename?}` Node disk persistence, with JSON files per account.
`{type: "memory"}` An in-process Map, for tests and one-shot scripts.

## Cursor

The NoteManager keeps a sync cursor (the last-synced block number). Subsequent `discoverNotes()` calls start from the cursor instead of from genesis, which keeps steady-state syncs fast. Clearing the cursor forces a full rescan, which can be slow on a cold start.

## Direct access

Usually you go through `session.exportAccount()`. The NoteManager isn't a public API of the session, but imports and mutations happen through these session methods:

-   `importReceivedNote(note)`: adds a note manually.
-   `discoverNotes()`: reconciles from the chain.
-   `exportAccount()`: takes a snapshot.
